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