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