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