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