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