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