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