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