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