chiark / gitweb /
7c211c51cc3d70902e559e08d21033ca53910da0
[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.44  2008/02/27 00:54:16  james
14  * *** empty log message ***
15  *
16  * Revision 1.43  2008/02/27 00:27:22  james
17  * *** empty log message ***
18  *
19  * Revision 1.42  2008/02/26 23:56:12  james
20  * *** empty log message ***
21  *
22  * Revision 1.41  2008/02/26 23:23:17  james
23  * *** empty log message ***
24  *
25  * Revision 1.40  2008/02/26 19:00:59  james
26  * *** empty log message ***
27  *
28  * Revision 1.39  2008/02/26 16:54:06  james
29  * *** empty log message ***
30  *
31  * Revision 1.38  2008/02/26 16:53:24  james
32  * *** empty log message ***
33  *
34  * Revision 1.37  2008/02/24 12:22:53  james
35  * *** empty log message ***
36  *
37  * Revision 1.36  2008/02/24 12:22:42  james
38  * *** empty log message ***
39  *
40  * Revision 1.35  2008/02/24 00:42:53  james
41  * *** empty log message ***
42  *
43  * Revision 1.34  2008/02/23 11:48:37  james
44  * *** empty log message ***
45  *
46  * Revision 1.33  2008/02/22 23:39:27  james
47  * *** empty log message ***
48  *
49  * Revision 1.32  2008/02/22 19:12:05  james
50  * *** empty log message ***
51  *
52  * Revision 1.31  2008/02/22 17:07:00  james
53  * *** empty log message ***
54  *
55  * Revision 1.30  2008/02/22 14:51:54  james
56  * *** empty log message ***
57  *
58  * Revision 1.29  2008/02/15 03:32:07  james
59  * *** empty log message ***
60  *
61  * Revision 1.28  2008/02/14 10:34:30  james
62  * *** empty log message ***
63  *
64  * Revision 1.27  2008/02/14 02:46:45  james
65  * *** empty log message ***
66  *
67  * Revision 1.26  2008/02/14 01:55:57  james
68  * *** empty log message ***
69  *
70  * Revision 1.25  2008/02/13 16:57:29  james
71  * *** empty log message ***
72  *
73  * Revision 1.24  2008/02/13 09:12:21  james
74  * *** empty log message ***
75  *
76  * Revision 1.23  2008/02/07 13:26:35  james
77  * *** empty log message ***
78  *
79  * Revision 1.22  2008/02/07 13:22:51  james
80  * *** empty log message ***
81  *
82  * Revision 1.21  2008/02/07 12:21:16  james
83  * *** empty log message ***
84  *
85  * Revision 1.20  2008/02/07 12:16:04  james
86  * *** empty log message ***
87  *
88  * Revision 1.19  2008/02/07 11:27:02  james
89  * *** empty log message ***
90  *
91  * Revision 1.18  2008/02/07 01:59:25  james
92  * *** empty log message ***
93  *
94  * Revision 1.17  2008/02/07 01:58:28  james
95  * *** empty log message ***
96  *
97  * Revision 1.16  2008/02/07 01:57:46  james
98  * *** empty log message ***
99  *
100  * Revision 1.15  2008/02/07 00:43:27  james
101  * *** empty log message ***
102  *
103  * Revision 1.14  2008/02/07 00:40:23  james
104  * *** empty log message ***
105  *
106  * Revision 1.13  2008/02/07 00:39:59  james
107  * *** empty log message ***
108  *
109  * Revision 1.12  2008/02/07 00:39:13  james
110  * *** empty log message ***
111  *
112  * Revision 1.11  2008/02/06 20:26:58  james
113  * *** empty log message ***
114  *
115  * Revision 1.10  2008/02/06 17:53:28  james
116  * *** empty log message ***
117  *
118  * Revision 1.9  2008/02/06 15:53:22  james
119  * *** empty log message ***
120  *
121  * Revision 1.8  2008/02/06 11:49:47  james
122  * *** empty log message ***
123  *
124  * Revision 1.7  2008/02/06 11:30:37  james
125  * *** empty log message ***
126  *
127  * Revision 1.6  2008/02/05 01:11:46  james
128  * *** empty log message ***
129  *
130  * Revision 1.5  2008/02/04 20:23:55  james
131  * *** empty log message ***
132  *
133  * Revision 1.4  2008/02/04 05:45:55  james
134  * ::
135  *
136  * Revision 1.3  2008/02/04 02:05:06  james
137  * *** empty log message ***
138  *
139  * Revision 1.2  2008/02/04 01:32:39  james
140  * *** empty log message ***
141  *
142  * Revision 1.1  2008/02/03 23:36:41  james
143  * *** empty log message ***
144  *
145  */
146
147
148 /* Termcap he say:
149
150 VT102:
151
152 vt102|dec vt102:\
153         :mi:\
154         :al=\E[L:dc=\E[P:dl=\E[M:ei=\E[4l:im=\E[4h:tc=vt100:
155
156 vt100|vt100-am|dec vt100 (w/advanced video):\
157         :am:bs:ms:xn:xo:\
158         :co#80:it#8:li#24:vt#3:\
159         :DO=\E[%dB:LE=\E[%dD:RA=\E[?7l:RI=\E[%dC:SA=\E[?7h:\
160         :UP=\E[%dA:\
161         :ac=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:\
162         :ae=^O:as=^N:bl=^G:cb=\E[1K:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\
163         :cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:ct=\E[3g:do=^J:\
164         :eA=\E(B\E)0:ho=\E[H:kb=^H:kd=\EOB:ke=\E[?1l\E>:kl=\EOD:\
165         :kr=\EOC:ks=\E[?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:\
166         :me=\E[m\017:mr=\E[7m:nd=\E[C:rc=\E8:\
167         :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:sc=\E7:se=\E[m:\
168         :sf=^J:so=\E[7m:sr=\EM:st=\EH:ta=^I:ue=\E[m:up=\E[A:\
169         :us=\E[4m:tc=vt100+fnkeys:
170
171 vt100+fnkeys|dec vt100 numeric keypad:\
172         :k0=\EOy:k5=\EOt:k6=\EOu:k7=\EOv:k8=\EOl:k9=\EOw:k;=\EOx:\
173         :tc=vt100+pfkeys:
174
175 vt100+pfkeys|dec vt100 numeric keypad:\
176         :@8=\EOM:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:tc=vt100+keypad:
177
178 vt100+keypad|dec vt100 numeric keypad no fkeys:\
179         :K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:
180
181 */
182
183 /*
184 so the parser needs to be able to at least do
185 CTRL-G
186 CTRL-H
187 CTRL-I
188 CTRL-J
189 CTRL-M
190 CTRL-N
191
192 CTRL-O
193 ESC7
194 ESC8
195 ESCH
196 ESCM
197 ESC> 
198
199 ESC[%dA
200 ESC[%dB
201 ESC[%dC
202 ESC[%dD
203 ESC[H
204 ESC[%d;%dH
205 ESC[J
206 ESC[K
207 ESC[1K
208 ESC[L
209 ESC[M
210 ESC[P
211
212 ESC[3g
213 ESC[4h
214 ESC[4l
215 ESC[m 
216 ESC[1m
217 ESC[4m
218 ESC[5m
219 ESC[7m
220 ESC[%d;%dr
221
222
223 ESC[?3l 
224 ESC[?4l 
225 ESC[?5l
226 ESC[?7h
227 ESC[?7h
228 ESC[?7l
229 ESC[?8h
230
231 ESC(B
232 ESC)0
233
234
235 TODO:
236
237 ESC(B
238 ESC)0
239
240 CTRL-O
241
242 ANSI:
243
244
245
246 ansi|ansi/pc-term compatible with color:\
247         :u6=\E[%i%d;%dR:u7=\E[6n:u9=\E[c:tc=ecma+color:\
248         :tc=klone+sgr:tc=ansi-m:
249 ansi-m|ansi-mono|ANSI X3.64-1979 terminal with ANSI.SYS compatible attributes:\
250         :5i:\
251         :AL=\E[%dL:DC=\E[%dP:DL=\E[%dM:DO=\E[%dB:IC=\E[%d@:\
252         :LE=\E[%dD:RI=\E[%dC:SF=\E[%dS:SR=\E[%dT:UP=\E[%dA:\
253         :cb=\E[1K:ch=\E[%i%dG:ct=\E[2g:cv=\E[%i%dd:ec=\E[%dX:ei=:\
254         :im=:kB=\E[Z:kI=\E[L:kb=^H:kd=\E[B:kl=\E[D:kr=\E[C:ku=\E[A:\
255         :nw=\r\E[S:pf=\E[4i:po=\E[5i:s0=\E(B:s1=\E)B:s2=\E*B:\
256         :s3=\E+B:ta=\E[I:tc=pcansi-m:
257 pcansi-m|pcansi-mono|ibm-pc terminal programs claiming to be ansi (mono mode):\
258         :am:bs:mi:ms:\
259         :co#80:it#8:li#24:\
260         :al=\E[L:bl=^G:bt=\E[Z:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\
261         :cm=\E[%i%d;%dH:cr=^M:ct=\E[2g:dc=\E[P:dl=\E[M:do=\E[B:\
262         :ho=\E[H:kb=^H:kd=\E[B:kh=\E[H:kl=\E[D:kr=\E[C:ku=\E[A:\
263         :le=\E[D:nd=\E[C:sf=^J:st=\EH:ta=^I:up=\E[A:\
264         :tc=klone+sgr-dumb:
265 klone+sgr-dumb|attribute control for ansi.sys displays (no ESC [ 11 m):\
266         :as=\E[12m:mb=\E[5m:md=\E[1m:me=\E[0;10m:mk=\E[8m:\
267         :mr=\E[7m:se=\E[m:so=\E[7m:ue=\E[m:us=\E[4m:tc=klone+acs:
268 klone+acs|alternate character set for ansi.sys displays:\
269         :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:\
270         :ae=\E[10m:as=\E[11m:
271 ecma+color|color control for ECMA-48-compatible terminals:\
272         :Co#8:NC#3:pa#64:\
273         :AB=\E[4%dm:AF=\E[3%dm:op=\E[39;49m:
274
275
276 Ignoreing ones in the VT102 spec
277
278 ESC[%d@
279 ESC[I
280 ESC[....R
281 ESC[%dS
282 ESC[%dT
283 ESC[X
284 ESC[Z
285
286 ESC[c
287 *ESC[%db
288 ESC[....d
289 ESC[....f
290 ESC[2g
291 ESC[4i
292 ESC[5i
293 ESC[6n
294
295 ESC(B
296 ESC)B
297 ESC*B
298 ESC+B
299
300
301 */
302
303 #include "project.h"
304 #include "syslog.h"
305
306 #define TABLE_LENGTH 128
307 #undef DEBUG
308
309
310 static char terminal_id[] = "vt102";
311
312 /* number of aditional chars after \033 ... to complete the escape if it's fixed length*/
313 int vt102_cmd_length[TABLE_LENGTH] = {
314   ['('] = 1,
315   [')'] = 1,
316   ['+'] = 1,
317   ['*'] = 1,
318   ['%'] = 1,
319   ['#'] = 1,
320   ['Y'] = 2,
321 };
322
323 /* method for determining end if if's not fixed length, -ve numbers from #defines, +ve are literals */
324 #define CSI_ENDER -1
325 int vt102_cmd_termination[TABLE_LENGTH] = {
326   [']'] = 7,
327   ['['] = CSI_ENDER,
328 };
329
330
331
332
333
334 static inline int
335 safe_ch (int c)
336 {
337   if (c < 32)
338     return ' ';
339   if (c > 126)
340     return ' ';
341   return c;
342 }
343
344 static inline int
345 csi_ender (int c)
346 {
347   if ((c >= 'a') && (c <= 'z'))
348     return 1;
349   if ((c >= 'A') && (c <= 'Z'))
350     return 1;
351   if ((c == '@'))
352     return 1;
353   return 0;
354 }
355
356 static inline int
357 ctrl_chr (int ch, int term)
358 {
359   if ((term > 0) && (ch == term))
360     return 0;
361   if (ch == 033)
362     return 0;
363   if ((ch > 0) && (ch < 040))
364     return 1;
365   return 0;
366 }
367
368
369 static inline int
370 in_margins (VT102 * v, CRT_Pos p)
371 {
372   if (v->pos.x < v->top_margin.x)
373     return 0;
374   if (v->pos.y < v->top_margin.y)
375     return 0;
376
377   if (v->pos.x > v->bottom_margin.x)
378     return 0;
379   if (v->pos.y > v->bottom_margin.y)
380     return 0;
381
382   return 1;
383 }
384
385 void
386 vt102_log_line (Context * c, int line)
387 {
388   CRT_Pos e = { c->v->current_width - 1, line };
389   CRT_Pos p = { 0, line };
390   char logbuf[4*(VT102_MAX_COLS + 1)],*logptr=logbuf;
391
392   if (!c->l)
393     return;
394
395
396   for (; e.x > 0; --e.x)
397     {
398       if (c->v->crt.screen[CRT_ADDR_POS (&e)].chr != ' ')
399         break;
400     }
401
402   for (; p.x <= e.x; ++p.x)
403     {
404       int ch = c->v->crt.screen[CRT_ADDR_POS (&p)].chr;
405       if (ch < 32)
406         ch = ' ';
407         logptr+=utf8_encode(logptr,ch);
408     }
409   *logptr=0;
410
411   c->l->log (c->l, logbuf);
412 }
413
414 /*Called for every upward scroll with same args*/
415 void
416 vt102_history (Context * c, CRT_Pos t, CRT_Pos b)
417 {
418 /*Only log if it scrolls off the top*/
419   if (t.y)
420     return;
421
422   t.x = 0;
423   history_add (c->h, &(c->v->crt.screen[CRT_ADDR_POS (&t)]));
424 }
425
426 void
427 vt102_clip_cursor (VT102 * v, CRT_Pos tl, CRT_Pos br)
428 {
429   if (v->pos.x < tl.x)
430     v->pos.x = tl.x;
431   if (v->pos.y < tl.y)
432     v->pos.y = tl.y;
433
434   if (v->pos.x > br.x)
435     v->pos.x = br.x;
436   if (v->pos.y > br.y)
437     v->pos.y = br.y;
438 }
439
440
441 void
442 vt102_cursor_normalize (VT102 * v)
443 {
444   CRT_Pos *top, *bottom;
445
446   if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
447     {
448       vt102_clip_cursor (v, v->top_margin, v->bottom_margin);
449     }
450   else
451     {
452       vt102_clip_cursor (v, v->screen_start, v->screen_end);
453     }
454 }
455
456
457 void
458 vt102_cursor_carriage_return (VT102 * v)
459 {
460    /*FISH*/ v->pos.x = v->top_margin.x;
461   v->pending_wrap = 0;
462 }
463
464 void
465 vt102_cursor_advance_line (Context * c)
466 {
467   VT102 *v = c->v;
468   int couldscroll = in_margins (v, v->pos);
469
470 /*have wraped off end of last line in scrolling region */
471 /* (|| not necessary, but shuts compiler up */
472   if (((v->pos.y == v->bottom_margin.y) || (v->pos.y == v->screen_end.y)) &&
473       (couldscroll))
474     {
475       vt102_log_line (c, v->pos.y);
476
477       vt102_history (c, v->top_margin, v->bottom_margin);
478
479       crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1, v->color);
480       return;
481     }
482
483   if (v->pos.y != v->screen_end.y)
484     v->pos.y++;
485   v->pending_wrap = 0;
486 }
487
488
489 void
490 vt102_cursor_retreat_line (Context * c)
491 {
492   VT102 *v = c->v;
493   int couldscroll = in_margins (v, v->pos);
494
495 /*have wraped off end of last line in scrolling region */
496 /* (|| not necessary, but shuts compiler up */
497   if (((v->pos.y == v->top_margin.y) || (v->pos.y == v->screen_start.y)) &&
498       (couldscroll))
499     {
500       vt102_log_line (c, v->pos.y);
501
502       crt_scroll_down (&v->crt, v->top_margin, v->bottom_margin, 1, v->color);
503       return;
504     }
505
506   if (v->pos.y != v->screen_start.y)
507     v->pos.y--;
508   v->pending_wrap = 0;
509 }
510
511
512 void
513 vt102_do_pending_wrap (Context * c)
514 {
515   VT102 *v = c->v;
516   int couldscroll = in_margins (v, v->pos);
517   int autowrap = v->private_modes[VT102_PRIVATE_MODE_AUTO_WRAP];
518
519   if (!v->pending_wrap)
520     return;
521
522 #if 0
523   fprintf (stderr, "ca: (%d,%d) autowrap %d couldscroll %d\n", v->pos.x,
524            v->pos.y, autowrap, couldscroll);
525 #endif
526
527 /*End of line but no autowrap, nothing to do*/
528   if (!autowrap)
529     return;
530
531 /*End of screen and not allowed to scroll, nothing to do*/
532   if ((v->pos.y == v->screen_end.y) && (!couldscroll))
533     return;
534
535   if (couldscroll)
536     {
537       v->pos.x = v->top_margin.x;
538     }
539   else
540     {
541       v->pos.x = 0;
542     }
543
544   vt102_cursor_advance_line (c);
545 }
546
547 void
548 vt102_cursor_advance (Context * c)
549 {
550   VT102 *v = c->v;
551
552   if (v->pos.x < v->bottom_margin.x)
553     {
554 /*Normal advance*/
555       v->pos.x++;
556       v->pending_wrap = 0;
557       return;
558     }
559   v->pending_wrap++;
560   if (!c->v->xn_glitch)
561     vt102_do_pending_wrap (c);
562 }
563
564
565
566 void
567 vt102_cursor_retreat (VT102 * v)
568 {
569   if (v->pos.x != v->top_margin.x)
570     {
571       v->pos.x--;
572     }
573
574   v->pending_wrap = 0;
575 }
576
577 void
578 vt102_reset_tabs (VT102 * v)
579 {
580   int i;
581
582   memset (v->tabs, 0, sizeof (v->tabs));
583
584   for (i = 0; i < VT102_MAX_COLS; i += 8)
585     {
586       v->tabs[i]++;
587     }
588 }
589 void
590 vt102_cursor_advance_tab (VT102 * v)
591 {
592   if (v->pos.x == v->bottom_margin.x)
593     return;
594   while (v->pos.x < v->bottom_margin.x)
595     {
596       v->pos.x++;
597       if (v->tabs[v->pos.x])
598         break;
599     }
600   v->pending_wrap = 0;
601 }
602
603 void
604 vt102_cursor_retreat_tab (VT102 * v)
605 {
606   if (v->pos.x == v->top_margin.x)
607     return;
608   while (v->pos.x > v->top_margin.x)
609     {
610       v->pos.x--;
611       if (v->tabs[v->pos.x])
612         break;
613     }
614   v->pending_wrap = 0;
615 }
616
617 vt102_cursor_home (VT102 * v)
618 {
619   v->pos = v->top_margin;
620   vt102_cursor_normalize (v);
621   v->pending_wrap = 0;
622
623 }
624
625 vt102_cursor_absolute (VT102 * v, int x, int y)
626 {
627   if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
628     {
629       v->pos.x = x + v->top_margin.x;
630       v->pos.y = y + v->top_margin.y;
631     }
632   else
633     {
634       v->pos.x = x;
635       v->pos.y = y;
636     }
637   vt102_cursor_normalize (v);
638   v->pending_wrap = 0;
639 }
640
641 vt102_cursor_relative (VT102 * v, int x, int y)
642 {
643   v->pos.x += x;
644   v->pos.y += y;
645   vt102_cursor_normalize (v);
646   v->pending_wrap = 0;
647 }
648
649
650
651 void
652 vt102_delete_from_line (VT102 * v, CRT_Pos p)
653 {
654   int n = v->bottom_margin.x - p.x;
655
656   if (n < 0)
657     return;
658
659   if (n)
660     {
661
662       memmove (&v->crt.screen[CRT_ADDR_POS (&p)],
663                &v->crt.screen[CRT_ADDR_POS (&p) + 1], sizeof (CRT_CA) * n);
664     }
665
666   v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].chr = ' ';
667 /*But not attr due to vt102 bug*/
668 }
669
670 void
671 vt102_insert_into_line (VT102 * v, CRT_Pos p)
672 {
673   int n = v->bottom_margin.x - p.x;
674
675   if (n < 0)
676     return;
677
678   if (n)
679     {
680
681       memmove (&v->crt.screen[CRT_ADDR_POS (&p) + 1],
682                &v->crt.screen[CRT_ADDR_POS (&p)], sizeof (CRT_CA) * n);
683     }
684
685   v->crt.screen[CRT_ADDR_POS (&p)].chr = ' ';
686   v->crt.screen[CRT_ADDR_POS (&p)].attr = CRT_ATTR_NORMAL;
687   v->crt.screen[CRT_ADDR_POS (&p)].color = CRT_COLOR_NORMAL;
688 }
689
690
691
692 void
693 vt102_change_mode (VT102 * v, int private, char *ns, int set)
694 {
695   int m;
696
697
698   if (*ns)
699     {
700       m = atoi (ns);
701     }
702   else
703     {
704       m = 1;
705     }
706
707   if (m < 0)
708     return;
709   if (m >= VT102_NMODES)
710     return;
711
712   if (private)
713     {
714       v->private_modes[m] = set;
715       switch (m)
716         {
717         case VT102_PRIVATE_MODE_CURSOR_MODE:
718           if (v->application_keypad_mode)
719             v->private_modes[m] = 0;
720 #if 0
721           fprintf (stderr, "APPLICATION CURSOR MODE %d wanted %d\n",
722                    v->private_modes[m], set);
723 #endif
724           break;
725         case VT102_PRIVATE_MODE_ORIGIN_MODE:
726           vt102_cursor_home (v);
727           break;
728         case VT102_PRIVATE_MODE_132COLS:
729           /* We don't implement 132 col mode - yet */
730
731           v->current_width =
732             v->
733             private_modes[VT102_PRIVATE_MODE_132COLS] ? VT102_COLS_132 :
734             VT102_COLS_80;
735
736           v->crt.width = v->current_width;
737           v->screen_end.x = v->current_width - 1;
738           v->top_margin = v->screen_start;
739           v->bottom_margin = v->screen_end;
740           vt102_cursor_home (v);
741           crt_cls (&v->crt);
742
743
744           break;
745         }
746
747     }
748   else
749     v->modes[m] = set;
750
751 #if 0
752   fprintf (stderr, "mode set=%d private=%d num=%d\n", set, private, m);
753 #endif
754 }
755
756 void
757 vt102_parse_mode_string (VT102 * v, char *buf, int len)
758 {
759   int private = 0;
760   char last = buf[len - 1];
761   char num[4];
762   int o;
763
764   memset (num, 0, sizeof (num));
765   o = sizeof (num) - 1;
766
767   len--;
768
769   if (*buf == '?')
770     {
771       private++;
772       buf++;
773       len--;
774     }
775
776   if (len < 0)
777     return;
778
779   while (len--)
780     {
781       if (*buf == ';')
782         {
783           vt102_change_mode (v, private, &num[o], last == 'h');
784           memset (num, 0, sizeof (num));
785           o = sizeof (num) - 1;
786           buf++;
787           continue;
788         }
789
790       num[0] = num[1];
791       num[1] = num[2];
792       num[2] = *buf;
793
794       if (o)
795         o--;
796
797       buf++;
798     }
799
800   vt102_change_mode (v, private, &num[o], last == 'h');
801
802 }
803
804
805 void
806 vt102_change_attr (VT102 * v, char *na)
807 {
808   int a;
809
810
811   if (*na)
812     {
813       a = atoi (na);
814     }
815   else
816     {
817       a = 0;
818     }
819
820   switch (a)
821     {
822     case 0:
823       v->attr = CRT_ATTR_NORMAL;
824       v->color = CRT_COLOR_NORMAL;
825       break;
826     case 1:
827       v->attr |= CRT_ATTR_BOLD;
828       break;
829     case 21:
830     case 22:
831       v->attr &= ~CRT_ATTR_BOLD;
832       break;
833     case 4:
834       v->attr |= CRT_ATTR_UNDERLINE;
835       break;
836     case 24:
837       v->attr &= ~CRT_ATTR_UNDERLINE;
838       break;
839     case 5:
840       v->attr |= CRT_ATTR_BLINK;
841       break;
842     case 25:
843       v->attr &= ~CRT_ATTR_BLINK;
844       break;
845     case 7:
846       v->attr |= CRT_ATTR_REVERSE;
847       break;
848     case 27:
849       v->attr &= ~CRT_ATTR_REVERSE;
850       break;
851     case 30:
852     case 31:
853     case 32:
854     case 33:
855     case 34:
856     case 35:
857     case 36:
858     case 37:
859       v->color &= ~CRT_COLOR_FG_MASK;
860       v->color |= ((a - 30) << CRT_COLOR_FG_SHIFT) & CRT_COLOR_FG_MASK;
861       break;
862     case 90:
863     case 91:
864     case 92:
865     case 93:
866     case 94:
867     case 95:
868     case 96:
869     case 97:
870       v->color &= ~CRT_COLOR_FG_MASK;
871       v->color |=
872         (((a -
873            90) | CRT_COLOR_INTENSITY) << CRT_COLOR_FG_SHIFT) &
874         CRT_COLOR_FG_MASK;
875       break;
876     case 39:
877     case 99:
878       v->color &= ~CRT_COLOR_FG_MASK;
879       v->color |=
880         (CRT_FGCOLOR_NORMAL << CRT_COLOR_FG_SHIFT) & CRT_COLOR_FG_MASK;
881       break;
882     case 40:
883     case 41:
884     case 42:
885     case 43:
886     case 44:
887     case 45:
888     case 46:
889     case 47:
890       v->color &= ~CRT_COLOR_BG_MASK;
891       v->color |= ((a - 40) << CRT_COLOR_BG_SHIFT) & CRT_COLOR_BG_MASK;
892       break;
893     case 100:
894     case 101:
895     case 102:
896     case 103:
897     case 104:
898     case 105:
899     case 106:
900     case 107:
901       v->color &= ~CRT_COLOR_BG_MASK;
902       v->color |=
903         (((a -
904            100) | CRT_COLOR_INTENSITY) << CRT_COLOR_BG_SHIFT) &
905         CRT_COLOR_BG_MASK;
906       break;
907     case 49:
908     case 109:
909       v->color &= ~CRT_COLOR_BG_MASK;
910       v->color |=
911         (CRT_BGCOLOR_NORMAL << CRT_COLOR_BG_SHIFT) & CRT_COLOR_BG_MASK;
912       break;
913
914     default:
915       ;
916 #if 0
917       fprintf (stderr, "unhandled SGR %d\n", a);
918 #endif
919     }
920
921 }
922
923
924 void
925 vt102_parse_attr_string (VT102 * v, char *buf, int len)
926 {
927   int private = 0;
928   char last = buf[len - 1];
929   char num[4];
930   int o;
931
932   memset (num, 0, sizeof (num));
933   o = sizeof (num) - 1;
934
935   len--;
936
937   if (len < 0)
938     return;
939
940   while (len--)
941     {
942       if (*buf == ';')
943         {
944           vt102_change_attr (v, &num[o]);
945           memset (num, 0, sizeof (num));
946           o = sizeof (num) - 1;
947           buf++;
948           continue;
949         }
950
951       num[0] = num[1];
952       num[1] = num[2];
953       num[2] = *buf;
954
955       if (o)
956         o--;
957
958       buf++;
959     }
960   vt102_change_attr (v, &num[o]);
961 }
962
963 void
964 vt102_save_state (VT102 * v)
965 {
966   v->saved.pos = v->pos;
967   v->saved.attr = v->attr;
968   v->saved.color = v->color;
969   v->saved.origin_mode = v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE];
970 }
971
972 void
973 vt102_restore_state (VT102 * v)
974 {
975   v->pos = v->saved.pos;
976   v->attr = v->saved.attr;
977   v->color = v->saved.color;
978   v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE] = v->saved.origin_mode;
979   vt102_cursor_normalize (v);
980   v->pending_wrap = 0;
981 }
982
983 void
984 vt102_regular_char (Context * c, VT102 * v, uint32_t ch)
985 {
986
987
988   vt102_do_pending_wrap (c);
989
990
991   if (v->modes[VT102_MODE_INSERT])
992     vt102_insert_into_line (v, v->pos);
993
994   v->last_reg_char = ch;
995
996
997   if (ch < VT102_CHARSET_SIZE)
998     {
999         int cs;
1000         if ((cs=vt102_charset_c0[ch])) {
1001                 ch=cs;
1002         } else if ((cs=charset_from_csid[v->g[v->cs]][ch])) {
1003                 ch=cs;
1004         }
1005     }
1006   v->crt.screen[CRT_ADDR_POS (&v->pos)].chr = ch;
1007   v->crt.screen[CRT_ADDR_POS (&v->pos)].attr = v->attr;
1008   v->crt.screen[CRT_ADDR_POS (&v->pos)].color = v->color;
1009   vt102_cursor_advance (c);
1010
1011 }
1012
1013 vt102_send_id (Context * c, char *buf)
1014 {
1015
1016   if (c->t)
1017     {
1018       int l = strlen (buf);
1019       c->t->xmit (c->t, buf, l);
1020     }
1021 }
1022
1023 void
1024 vt102_scs (Context * c, int g, int s)
1025 {
1026   VT102 *v = c->v;
1027   int cs = VT102_CSID_US;
1028
1029
1030   switch (s)
1031     {
1032     case 'A':
1033       cs = VT102_CSID_UK;
1034       break;
1035     case '1':
1036     case '2':
1037     case 'B':
1038       cs = VT102_CSID_US;
1039       break;
1040     case '0':
1041       cs = VT102_CSID_GL;
1042       break;
1043     }
1044
1045   switch (g)
1046     {
1047     case '(':
1048       v->g[0] = cs;
1049       break;
1050     case ')':
1051       v->g[1] = cs;
1052       break;
1053     }
1054
1055 }
1056
1057 void
1058 vt102_parse_csi (Context * c, char *buf, int len)
1059 {
1060   char last;
1061   char *ptr;
1062   char *arg = buf + 1;
1063   int narg;
1064
1065   VT102 *v = c->v;
1066
1067   buf[len] = 0;
1068
1069   last = buf[len - 1];
1070 #if 0
1071   buf[len - 1] = 0;
1072 #endif
1073
1074   if (len > 2)
1075     {
1076       narg = atoi (arg);
1077     }
1078   else
1079     {
1080       narg = 1;
1081     }
1082
1083   switch (buf[0])
1084     {
1085     case '[':
1086       switch (last)
1087         {
1088         case '@':
1089           while (narg--)
1090             vt102_insert_into_line (v, v->pos);
1091           break;
1092         case 'A':
1093           vt102_cursor_relative (v, 0, -narg);
1094           break;
1095         case 'e':
1096         case 'B':
1097           vt102_cursor_relative (v, 0, narg);
1098           break;
1099         case 'a':
1100         case 'C':
1101           vt102_cursor_relative (v, narg, 0);
1102           break;
1103         case 'D':
1104           vt102_cursor_relative (v, -narg, 0);
1105           break;
1106         case 'E':
1107           vt102_cursor_relative (v, 0, narg);
1108           vt102_cursor_carriage_return (v);
1109           break;
1110         case 'F':
1111           vt102_cursor_relative (v, 0, -narg);
1112           vt102_cursor_carriage_return (v);
1113           break;
1114         case 'G':
1115           vt102_cursor_absolute (v, narg - 1, v->pos.y);
1116           break;
1117         case 'H':
1118         case 'f':
1119           {
1120             int x, y;
1121
1122             y = narg - 1;
1123
1124             ptr = index (arg, ';');
1125             if (ptr)
1126               x = atoi (ptr + 1) - 1;
1127             else
1128               x = 0;
1129
1130             vt102_cursor_absolute (v, x, y);
1131           }
1132           break;
1133         case 'I':
1134           while (narg--)
1135             vt102_cursor_advance_tab (c->v);
1136           break;
1137         case 'J':
1138           if (len == 2)
1139             narg = 0;           /*Different default */
1140           switch (narg)
1141             {
1142             case 0:
1143               crt_erase (&v->crt, v->pos, v->screen_end, 1, v->color);
1144               break;
1145             case 1:
1146               crt_erase (&v->crt, v->screen_start, v->pos, 1, v->color);
1147               break;
1148             case 2:
1149               crt_erase (&v->crt, v->screen_start, v->screen_end, 1,
1150                          v->color);
1151               break;
1152             }
1153           break;
1154         case 'K':
1155           {
1156             CRT_Pos ls = { 0, v->pos.y };
1157             CRT_Pos le = { v->current_width - 1, v->pos.y };
1158             if (len == 2)
1159               narg = 0;         /*Different default */
1160
1161             switch (narg)
1162               {
1163               case 0:
1164                 crt_erase (&v->crt, v->pos, le, 1, v->color);
1165                 break;
1166               case 1:
1167                 crt_erase (&v->crt, ls, v->pos, 1, v->color);
1168                 break;
1169               case 2:
1170                 crt_erase (&v->crt, ls, le, 1, v->color);
1171                 break;
1172               }
1173           }
1174           break;
1175
1176         case 'L':
1177           if ((v->pos.y >= v->top_margin.y)
1178               && (v->pos.y <= v->bottom_margin.y))
1179             {
1180               while (narg--)
1181                 crt_scroll_down (&v->crt, v->pos, v->bottom_margin, 1,
1182                                  v->color);
1183             }
1184           break;
1185
1186         case 'M':
1187           if ((v->pos.y >= v->top_margin.y)
1188               && (v->pos.y <= v->bottom_margin.y))
1189             {
1190               while (narg--)
1191                 {
1192                   vt102_history (c, v->pos, v->bottom_margin);
1193                   crt_scroll_up (&v->crt, v->pos, v->bottom_margin, 1,
1194                                  v->color);
1195                 }
1196             }
1197           break;
1198         case 'P':
1199           while (narg--)
1200             vt102_delete_from_line (v, v->pos);
1201           break;
1202         case 'S':
1203           while (narg--)
1204             {
1205               vt102_history (c, v->top_margin, v->bottom_margin);
1206               crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1,
1207                              v->color);
1208             }
1209           break;
1210         case 'T':
1211           while (narg--)
1212             crt_scroll_down (&v->crt, v->top_margin, v->bottom_margin, 1,
1213                              v->color);
1214           break;
1215         case 'X':
1216           {
1217             CRT_Pos end = v->pos;
1218             if (!narg)
1219               narg++;
1220
1221             end.x += narg - 1;
1222             if (end.x > v->bottom_margin.x)
1223               end.x = v->bottom_margin.x;
1224
1225             crt_erase (&v->crt, v->pos, end, 1, v->color);
1226           }
1227           break;
1228         case 'Z':
1229           while (narg--)
1230             vt102_cursor_retreat_tab (c->v);
1231           break;
1232         case '`':
1233           vt102_cursor_absolute (v, narg - 1, v->pos.y);
1234           break;
1235         case 'b':
1236           while (narg--)
1237             vt102_regular_char (c, v, v->last_reg_char);
1238           break;
1239         case 'c':
1240           vt102_send_id (c, "\033[?2c");
1241           break;
1242         case 'd':
1243           vt102_cursor_absolute (v, v->pos.x, narg - 1);
1244           break;
1245         case 'g':
1246           if (len == 2)
1247             narg = 0;           /*Different default */
1248
1249           switch (narg)
1250             {
1251             case 0:
1252               v->tabs[v->pos.x] = 0;
1253               break;
1254             case 2:            //FIXME: - LA120 says current line only WTF?
1255             case 3:
1256               memset (v->tabs, 0, sizeof (v->tabs));
1257               break;
1258             }
1259           break;
1260
1261         case 'i':              //Printer commands
1262           //FIXME
1263           break;
1264         case 'h':
1265         case 'l':
1266           vt102_parse_mode_string (v, &buf[1], len - 1);
1267           break;
1268
1269
1270         case 'm':
1271           vt102_parse_attr_string (v, &buf[1], len - 1);
1272           break;
1273         case 'n':              //Device status report
1274           switch (buf[1])
1275             {
1276             case '5':
1277               vt102_send_id (c, "\033[0n");
1278               break;
1279             case '6':
1280               if (c->t)
1281                 {
1282                   char buf[16];
1283                   int i;
1284                   i =
1285                     sprintf (buf, "\033[%d;%dR", v->pos.y + 1, v->pos.x + 1);
1286                   c->t->xmit (c->t, buf, i);
1287                 }
1288               break;
1289             default:
1290               //?15n printer status
1291               log_f (c->l, "<%s:%d unhandled DSR: \\033%s>", __FILE__,
1292                      __LINE__, buf);
1293             }
1294           break;
1295         case 'q':              //Load LED on off 
1296           break;
1297         case 'r':
1298           v->top_margin = v->screen_start;
1299           v->bottom_margin = v->screen_end;
1300
1301           if ((len > 2) && (ptr = index (arg, ';')))
1302             {
1303               ptr++;
1304               v->top_margin.y = narg - 1;
1305               v->bottom_margin.y = atoi (ptr) - 1;
1306             }
1307
1308           if (v->top_margin.y < v->screen_start.y)
1309             v->top_margin.y = v->screen_start.y;
1310           if (v->top_margin.y > v->screen_end.y)
1311             v->top_margin.y = v->screen_end.y;
1312           if (v->bottom_margin.y < v->screen_start.y)
1313             v->bottom_margin.y = v->screen_start.y;
1314           if (v->bottom_margin.y > v->screen_end.y)
1315             v->bottom_margin.y = v->screen_end.y;
1316
1317           vt102_cursor_home (v);
1318           break;
1319         case 's':
1320           v->saved.pos = v->pos;
1321           break;
1322         case 'u':
1323           v->pos = v->saved.pos;
1324           vt102_cursor_normalize (v);
1325           v->pending_wrap = 0;
1326           break;
1327         case 'y':              //Invoke confidence test
1328           break;
1329         case 'z':              //request terminal parameters
1330           break;
1331
1332         default:
1333           log_f (c->l, "<%s:%d unhandled CSI: \\033%s>", __FILE__, __LINE__,
1334                  buf);
1335
1336           ;
1337         }
1338       break;
1339     default:
1340       log_f (c->l, "<%s:%d unhandled sequence: \\033%s>", __FILE__,
1341              __LINE__, buf);
1342       ;
1343     }
1344
1345
1346
1347 }
1348
1349 void
1350 vt102_parse_esc (Context * c)
1351 {
1352   VT102 *v = c->v;
1353   VT102_parser *p = &v->parser;
1354
1355 #ifdef DEBUG
1356   p->cmd_buf[p->cmd_ptr] = 0;
1357   log_f (c->l, "<cmd in  x=%3d y=%2d aw=%d vt=%d <ESC>%s >", v->pos.x,
1358          v->pos.y, v->pending_wrap,
1359          !v->private_modes[VT102_PRIVATE_MODE_VT52], p->cmd_buf);
1360 #endif
1361
1362   if (!v->private_modes[VT102_PRIVATE_MODE_VT52])
1363     {
1364       int ate = 1;
1365
1366       switch (p->cmd_buf[0])
1367         {
1368         case 'A':
1369           vt102_cursor_relative (v, 0, -1);
1370           break;
1371         case 'B':
1372           vt102_cursor_relative (v, 0, 1);
1373           break;
1374         case 'C':
1375           vt102_cursor_relative (v, 1, 0);
1376           break;
1377         case 'D':
1378           vt102_cursor_relative (v, -1, 0);
1379           break;
1380         case 'F':
1381           v->cs = 1;
1382           v->g[1] = VT102_CSID_VT52;
1383           break;
1384         case 'G':
1385           v->cs = 0;
1386           v->g[0] = VT102_CSID_US;
1387           break;
1388         case 'H':
1389           vt102_cursor_absolute (v, 0, 0);
1390           break;
1391         case 'I':
1392           vt102_cursor_retreat_line (c);
1393           break;
1394         case 'J':
1395           crt_erase (&v->crt, v->pos, v->screen_end, 1, v->color);
1396           break;
1397         case 'K':
1398           {
1399             CRT_Pos le = { v->current_width - 1, v->pos.y };
1400             crt_erase (&v->crt, v->pos, le, 1, v->color);
1401           }
1402           break;
1403         case 'Y':
1404           vt102_cursor_absolute (v, p->cmd_buf[2] - 040, p->cmd_buf[1] - 040);
1405           break;
1406         case 'V':              //Print current line
1407           break;
1408         case 'W':              //Printer on
1409           break;
1410         case 'X':              //printer off
1411           break;
1412         case ']':              //print screen
1413           break;
1414         case 'Z':              //ID
1415           vt102_send_id (c, "\033/K");
1416           break;
1417         case '^':              //Autoprint on
1418           break;
1419         case '_':              //Autoprint off
1420           break;
1421         case '=':
1422           v->application_keypad_mode = 1;
1423           break;
1424         case '>':
1425           v->application_keypad_mode = 0;
1426           break;
1427         default:
1428           ate = 0;
1429         }
1430       if (ate)
1431         return;
1432     }
1433
1434
1435 /*If you edit this switch don't forget to edit the length and termination tables*/
1436   switch (p->cmd_buf[0])
1437     {
1438     case 'D':
1439       vt102_cursor_advance_line (c);
1440       break;
1441
1442     case 'E':
1443       vt102_cursor_advance_line (c);
1444       v->pos.x = v->top_margin.x;
1445       vt102_cursor_normalize (v);
1446       v->pending_wrap = 0;
1447       break;
1448     case 'H':
1449       v->tabs[v->pos.x]++;
1450       break;
1451     case 'M':
1452       vt102_cursor_retreat_line (c);
1453       break;
1454     case 'N':                  //select G2 for one char
1455       break;
1456     case 'O':                  //select G3 for one char
1457       break;
1458     case 'Z':
1459       vt102_send_id (c, terminal_id);
1460       break;
1461     case 'c':
1462       vt102_reset (v);
1463
1464
1465       break;
1466     case '=':
1467       v->application_keypad_mode = 1;
1468       break;
1469     case '>':
1470       v->application_keypad_mode = 0;
1471       break;
1472
1473     case '#':
1474       switch (p->cmd_buf[1])
1475         {
1476         case '3':              //top of double height line
1477         case '4':              //bottom of double height line
1478         case '5':              //single width line
1479         case '6':              //double width line
1480           break;
1481         case '8':
1482            /*DECALN*/
1483           {
1484             int i;
1485             crt_erase (&v->crt, v->screen_start, v->screen_end, 1,
1486                        CRT_COLOR_NORMAL);
1487             for (i = 0; i < CRT_ADDR_POS (&v->screen_end); ++i)
1488               v->crt.screen[i].chr = 'E';
1489           }
1490           break;
1491         default:
1492
1493           log_f (c->l,
1494                  "<%s:%d unhandled ESC: \\033 \\043 \\%03o (ESC # %c)>",
1495                  __FILE__, __LINE__, p->cmd_buf[1], safe_ch (p->cmd_buf[1]));
1496
1497         }
1498       break;
1499     case '<':
1500       /*Set ansi mode - ignored */
1501       break;
1502
1503     case '7':
1504       vt102_save_state (v);
1505       break;
1506     case '8':
1507       vt102_restore_state (v);
1508       break;
1509     case ']':                  /*Set various titles */
1510       //FIXME:
1511       break;
1512     case '[':
1513       vt102_parse_csi (c, p->cmd_buf, p->cmd_ptr);
1514       break;
1515     case '(':                  /*Charsets */
1516     case ')':
1517     case '+':
1518     case '*':
1519     case '%':
1520       vt102_scs (c, p->cmd_buf[0], p->cmd_buf[1]);
1521       break;
1522     default:
1523       log_f (c->l, "<%s:%d unhandled ESC: \\033 \\%03o (ESC %c)>", __FILE__,
1524              __LINE__, p->cmd_buf[0], safe_ch (p->cmd_buf[0]));
1525
1526       ;
1527     }
1528
1529   p->cmd_buf[p->cmd_ptr] = 0;
1530 #ifdef DEBUG
1531   log_f (c->l, "<cmd out x=%3d y=%2d aw=%d>", v->pos.x, v->pos.y,
1532          v->pending_wrap);
1533 #endif
1534 }
1535
1536 void
1537 vt102_status_line (VT102 * v, char *str)
1538 {
1539   int i = v->current_width - 1;
1540   CRT_CA *ca = &v->crt.screen[CRT_ADDR (VT102_STATUS_ROW, 0)];
1541
1542   for (i = 0; i < v->current_width; ++i)
1543     {
1544       ca->attr = CRT_ATTR_REVERSE;
1545       ca->color = CRT_COLOR_NORMAL;
1546       ca->chr = *str ? *str : ' ';
1547       if (*str)
1548         str++;
1549       ca++;
1550     }
1551
1552   for (; i < VT102_MAX_COLS; ++i)
1553     {
1554       ca->attr = CRT_ATTR_NORMAL;
1555       ca->color = CRT_COLOR_NORMAL;
1556       ca->chr = ' ';
1557       ca++;
1558     }
1559
1560 }
1561
1562
1563 void
1564 vt102_parser_reset (VT102_parser * p)
1565 {
1566   p->in_cmd = 0;
1567   p->cmd_more_bytes = 0;
1568   p->cmd_termination = 0;
1569   p->in_escape = 0;
1570 }
1571
1572
1573 void
1574 vt102_reset_state (VT102 * v)
1575 {
1576   vt102_parser_reset (&v->parser);
1577
1578   v->attr = CRT_ATTR_NORMAL;
1579   v->color = CRT_COLOR_NORMAL;
1580
1581   v->application_keypad_mode = 0;
1582
1583   v->current_width = VT102_COLS_80;
1584   v->crt.width = v->current_width;
1585   v->screen_end.x = v->current_width - 1;
1586
1587   v->top_margin = v->screen_start;
1588   v->bottom_margin = v->screen_end;
1589
1590   memset (v->modes, 0, VT102_NMODES);
1591   memset (v->private_modes, 0, VT102_NMODES);
1592
1593   v->private_modes[VT102_PRIVATE_MODE_AUTO_WRAP] = 1;
1594   v->private_modes[VT102_PRIVATE_MODE_AUTO_REPEAT] = 1;
1595   v->private_modes[VT102_PRIVATE_MODE_SHOW_CURSOR] = 1;
1596   v->private_modes[VT102_PRIVATE_MODE_VT52] = 1;
1597   v->modes[VT102_MODE_LOCAL_ECHO_OFF] = 1;
1598
1599   vt102_reset_tabs (v);
1600
1601   v->g[0] = v->g[1] = VT102_CSID_US;
1602   v->cs = 0;
1603 }
1604
1605 static void
1606 pre_parse_cmd (int ch, VT102_parser * p)
1607 {
1608   if (ch > TABLE_LENGTH)
1609     return;
1610   if (ch < 0)
1611     return;
1612
1613   p->cmd_more_bytes = 0;
1614   p->in_cmd = 0;
1615
1616   p->cmd_termination = vt102_cmd_termination[ch];
1617   if (p->cmd_termination)
1618     {
1619       p->in_cmd++;
1620       return;
1621     }
1622
1623   p->cmd_more_bytes = vt102_cmd_length[ch];
1624
1625   if (p->cmd_more_bytes)
1626     {
1627       p->in_cmd++;
1628       return;
1629     }
1630 }
1631
1632 void
1633 vt102_parse_char (Context * c, int ch)
1634 {
1635   VT102 *v = c->v;
1636   VT102_parser *p = &v->parser;
1637
1638 #if 0
1639   log_f (c->l, "char %3d %c   ie=%d ic=%d cmb=%d ct=%3d    %2d %2d %d", ch,
1640          safe_ch (ch), p->in_escape, p->in_cmd, p->cmd_more_bytes,
1641          p->cmd_termination, v->pos.x, v->pos.y, v->pending_wrap);
1642 #endif
1643
1644 /* Turn anything non-ascii into '?' */
1645 #if 0
1646   if ((ch != SYM_CHAR_RESET) && (ch != 0xb9) && (ch > 127))
1647     {
1648       ch = '?';
1649     }
1650 #endif
1651
1652
1653 #if 0
1654   if (p->dca_ptr == 2)
1655     {
1656       p->in_dca = 0;
1657     }
1658 #endif
1659   if (ch == SYM_CHAR_RESET)
1660     {
1661       vt102_reset_state (v);
1662     }
1663   else if (p->in_cmd && !ctrl_chr (ch, p->cmd_termination))
1664     {
1665       p->cmd_buf[p->cmd_ptr++] = ch;
1666       if (p->cmd_ptr == VT102_CMD_LEN)
1667         p->in_cmd = 0;
1668       if (p->cmd_more_bytes)
1669         {
1670           p->cmd_more_bytes--;
1671
1672
1673           if (!p->cmd_more_bytes == 1)
1674             p->in_cmd = 0;
1675         }
1676
1677       switch (p->cmd_termination)
1678         {
1679         case 0:
1680           break;
1681         default:
1682           if (p->cmd_termination == ch)
1683             p->in_cmd = 0;
1684           break;
1685         case CSI_ENDER:
1686           if (csi_ender (ch))
1687             p->in_cmd = 0;
1688           break;
1689         }
1690
1691       if (!p->in_cmd)
1692         {
1693           vt102_parse_esc (c);
1694           p->cmd_more_bytes = 0;
1695           p->cmd_termination = 0;
1696         }
1697     }
1698   else if (p->in_escape && !ctrl_chr (ch, 0))
1699     {
1700       p->cmd_ptr = 0;
1701       p->cmd_buf[p->cmd_ptr++] = ch;
1702       p->in_escape = 0;
1703
1704       pre_parse_cmd (ch, p);
1705
1706       if (!p->in_cmd)
1707         vt102_parse_esc (c);
1708     }
1709   else if (ch == 0x9b)          /*One byte CSI */
1710     {
1711       p->cmd_ptr = 0;
1712       p->cmd_buf[p->cmd_ptr++] = '[';
1713
1714       pre_parse_cmd (ch, p);
1715     }
1716   else
1717     {
1718 #ifdef DEBUG
1719       if (ch != 27)
1720         log_f (c->l,
1721                "<chr in  x=%3d y=%2d aw=%d  \\%03o %3d %c",
1722                v->pos.x, v->pos.y, v->pending_wrap, ch, ch, safe_ch (ch));
1723
1724 #endif
1725
1726       switch (ch)
1727         {
1728 #if 0
1729          /*NUL*/ case 0:
1730          /*SOH*/ case 1:
1731          /*STX*/ case 2:
1732          /*ETX*/ case 3:
1733          /*EOT*/ case 4:
1734           break;
1735 #endif
1736          /*ENQ*/ case 5:
1737           vt102_send_id (c, terminal_id);
1738           break;
1739 #if 0
1740          /*ACK*/ case 6:
1741         break;
1742 #endif
1743          /*BEL*/ case 7:
1744                 //FIXME beep
1745           break;
1746          /*BS*/ case 8:
1747           vt102_cursor_retreat (c->v);
1748           break;
1749          /*HT*/ case 9:
1750           vt102_cursor_advance_tab (c->v);
1751           break;
1752          /*LF*/ case 10:
1753          /*VT*/ case 11:
1754          /*FF*/ case 12:
1755           vt102_cursor_advance_line (c);
1756           if (!v->modes[VT102_MODE_NEWLINE_MODE])
1757             break;
1758          /*CR*/ case 13:
1759           vt102_cursor_carriage_return (v);
1760           break;
1761          /*SO*/ case 14:
1762           /*select G1 */
1763           v->cs = 1;
1764           break;
1765          /*SI*/ case 15:
1766           /*select G0 */
1767           v->cs = 0;
1768           break;
1769 #if 0
1770          /*DLE*/ case 16:
1771         /*DC1 */ case 17:
1772         /*DC2 */ case 18:
1773         /*DC3 */ case 19:
1774         /*DC4 */ case 20:
1775          /*NAK*/ case 21:
1776          /*SYN*/ case 22:
1777          /*ETB*/ case 23:
1778          /*CAN*/ case 24:
1779          /*EM*/ case 25:
1780          /*SUB*/ case 26:
1781           break;
1782 #endif
1783          /*ESC*/ case 27:
1784           p->in_escape++;
1785           return;
1786 #if 0
1787          /*FS*/ case 28:
1788          /*GS*/ case 29:
1789          /*RS*/ case 30:
1790          /*US*/ case 31:
1791          /*DEL*/ case 127:
1792           break;
1793 #endif
1794         /*regular character */ default:
1795           vt102_regular_char (c, v, ch);
1796         }
1797
1798 #ifdef DEBUG
1799       if (ch != 27)
1800         log_f (c->l, "<chr out x=%3d y=%2d aw=%d>", v->pos.x, v->pos.y,
1801                v->pending_wrap);
1802 #endif
1803     }
1804
1805   v->crt.pos = v->pos;
1806   v->crt.hide_cursor =
1807     v->private_modes[VT102_PRIVATE_MODE_SHOW_CURSOR] ? 0 : 1;
1808
1809   if (v->current_line.y != v->pos.y)
1810     {
1811       vt102_log_line (c, v->current_line.y);
1812       v->current_line = v->pos;
1813     }
1814
1815   if (c->d)
1816     cmd_show_status (c->d, c);
1817 }
1818
1819 void
1820 vt102_send (Context * c, uint8_t key)
1821 {
1822   uint8_t ch;
1823
1824   if (!c->t)
1825     return;
1826
1827 #if 0
1828   fprintf (stderr, "vts: %d(%c)\n", key, (key > 31) ? key : ' ');
1829 #endif
1830   if ((key > 31) && (key < 127))
1831     {
1832       c->t->xmit (c->t, &key, 1);
1833       return;
1834     }
1835
1836   switch (key)
1837     {
1838      /*NUL*/ case 0:
1839      /*SOH*/ case 1:
1840      /*STX*/ case 2:
1841      /*ETX*/ case 3:
1842      /*EOT*/ case 4:
1843      /*ENQ*/ case 5:
1844      /*ACK*/ case 6:
1845      /*BEL*/ case 7:
1846      /*BS*/ case 8:
1847      /*HT*/ case 9:
1848      /*LF*/ case 10:
1849      /*VT*/ case 11:
1850      /*FF*/ case 12:
1851       c->t->xmit (c->t, &key, 1);
1852       break;
1853      /*CR*/ case 13:
1854       c->t->xmit (c->t, &key, 1);
1855       if (c->v->modes[VT102_MODE_NEWLINE_MODE])
1856         {
1857           ch = 10;
1858           c->t->xmit (c->t, &ch, 1);
1859         }
1860       break;
1861      /*SO*/ case 14:
1862      /*SI*/ case 15:
1863      /*DLE*/ case 16:
1864     /*DC1 */ case 17:
1865     /*DC2 */ case 18:
1866     /*DC3 */ case 19:
1867     /*DC4 */ case 20:
1868      /*NAK*/ case 21:
1869      /*SYN*/ case 22:
1870      /*ETB*/ case 23:
1871      /*CAN*/ case 24:
1872      /*EM*/ case 25:
1873      /*SUB*/ case 26:
1874       c->t->xmit (c->t, &key, 1);
1875       break;
1876      /*ESC*/ case 27:
1877      /*FS*/ case 28:
1878      /*GS*/ case 29:
1879      /*RS*/ case 30:
1880      /*US*/ case 31:
1881      /*DEL*/ case 127:
1882       c->t->xmit (c->t, &key, 1);
1883       break;
1884
1885     case KEY_UP:
1886     case KEY_DOWN:
1887     case KEY_RIGHT:
1888     case KEY_LEFT:
1889     case KEY_HOME:
1890     case KEY_MIDDLE:
1891     case KEY_END:
1892
1893       if (c->v->private_modes[VT102_PRIVATE_MODE_CURSOR_MODE])
1894         {
1895           uint8_t buf[] = { 033, 'O', 'A' + (key - KEY_UP) };
1896           c->t->xmit (c->t, &buf, sizeof (buf));
1897         }
1898       else
1899         {
1900           uint8_t buf[] = { 033, '[', 'A' + (key - KEY_UP) };
1901           c->t->xmit (c->t, &buf, sizeof (buf));
1902         }
1903       break;
1904     case KEY_STAR:
1905     case KEY_PLUS:
1906     case KEY_COMMA:
1907     case KEY_PERIOD:
1908     case KEY_DIVIDE:
1909     case KEY_0:
1910     case KEY_1:
1911     case KEY_2:
1912     case KEY_3:
1913     case KEY_4:
1914     case KEY_5:
1915     case KEY_6:
1916     case KEY_7:
1917     case KEY_8:
1918     case KEY_9:
1919       if (c->v->application_keypad_mode)
1920         {
1921           uint8_t buf[] = { 033, 'O', 'a' + (key - KEY_154) };
1922           c->t->xmit (c->t, &buf, sizeof (buf));
1923         }
1924       else
1925         {
1926           static char kpoff[KEY_NUM] = {
1927             [KEY_STAR] = '*',
1928             [KEY_PLUS] = '+',
1929             [KEY_COMMA] = ',',
1930             [KEY_MINUS] = '-',
1931             [KEY_PERIOD] = '.',
1932             [KEY_DIVIDE] = '/',
1933             [KEY_0] = '0',
1934             [KEY_1] = '1',
1935             [KEY_2] = '2',
1936             [KEY_3] = '3',
1937             [KEY_4] = '4',
1938             [KEY_5] = '5',
1939             [KEY_6] = '6',
1940             [KEY_7] = '7',
1941             [KEY_8] = '8',
1942             [KEY_9] = '9'
1943           };
1944
1945           c->t->xmit (c->t, &kpoff[key], 1);
1946         }
1947       break;
1948     case KEY_ENTER:
1949       if (c->v->application_keypad_mode)
1950         {
1951           uint8_t buf[] = { 033, 'O', 'M' };
1952           c->t->xmit (c->t, &buf, sizeof (buf));
1953         }
1954       else
1955         {
1956           ch = 13;
1957           c->t->xmit (c->t, &ch, 1);
1958           if (c->v->modes[VT102_MODE_NEWLINE_MODE])
1959             {
1960               ch = 10;
1961               c->t->xmit (c->t, &ch, 1);
1962             }
1963         }
1964       break;
1965     case KEY_PF1:
1966     case KEY_PF2:
1967     case KEY_PF3:
1968     case KEY_PF4:
1969       {
1970         uint8_t buf[] = { 033, 'O', 'P' + (key - KEY_PF1) };
1971         c->t->xmit (c->t, &buf, sizeof (buf));
1972       }
1973       break;
1974     case KEY_INSERT:
1975     case KEY_DELETE:
1976     case KEY_PGUP:
1977     case KEY_PGDN:
1978       {
1979         uint8_t buf[] = { 033, '[', '0' + (key - KEY_180), '~' };
1980         c->t->xmit (c->t, &buf, sizeof (buf));
1981       }
1982       break;
1983     }
1984
1985 }
1986
1987 void
1988 vt102_reset (VT102 * v)
1989 {
1990   VT102_parser *p = &v->parser;
1991
1992
1993   crt_cls (&v->crt);
1994   v->current_line = v->pos;
1995   v->pending_wrap = 0;
1996
1997   v->screen_start.x = 0;
1998   v->screen_start.y = 0;
1999   v->current_width = VT102_COLS_80;
2000   v->crt.width = v->current_width;
2001   v->screen_end.x = v->current_width - 1;
2002   v->screen_end.y = VT102_ROWS - 1;
2003
2004   vt102_cursor_home (v);
2005   vt102_status_line (v, "");
2006
2007   vt102_reset_tabs (v);
2008   v->current_line = v->pos;
2009
2010   vt102_parser_reset (p);
2011   vt102_reset_state (v);
2012
2013   vt102_save_state (v);
2014
2015   v->last_reg_char = ' ';
2016 }
2017
2018 VT102 *
2019 vt102_new (void)
2020 {
2021   VT102 *v;
2022
2023   v = (VT102 *) malloc (sizeof (VT102));
2024
2025   v->xn_glitch = 1;
2026
2027   vt102_reset (v);
2028
2029
2030   return v;
2031 }
2032
2033 void
2034 vt102_set_ansi (VT102 * v, int ansi)
2035 {
2036   v->xn_glitch = ansi ? 0 : 1;
2037 }
2038
2039 void
2040 vt102_free (VT102 * v)
2041 {
2042   free (v);
2043 }