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