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