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.6  2008/02/05 01:11:46  james
14  * *** empty log message ***
15  *
16  * Revision 1.5  2008/02/04 20:23:55  james
17  * *** empty log message ***
18  *
19  * Revision 1.4  2008/02/04 05:45:55  james
20  * ::
21  *
22  * Revision 1.3  2008/02/04 02:05:06  james
23  * *** empty log message ***
24  *
25  * Revision 1.2  2008/02/04 01:32:39  james
26  * *** empty log message ***
27  *
28  * Revision 1.1  2008/02/03 23:36:41  james
29  * *** empty log message ***
30  *
31  */
32
33
34 /* Termcap he say:
35
36 vt102|dec vt102:\
37         :mi:\
38         :al=\E[L:dc=\E[P:dl=\E[M:ei=\E[4l:im=\E[4h:tc=vt100:
39
40 vt100|vt100-am|dec vt100 (w/advanced video):\
41         :am:bs:ms:xn:xo:\
42         :co#80:it#8:li#24:vt#3:\
43         :DO=\E[%dB:LE=\E[%dD:RA=\E[?7l:RI=\E[%dC:SA=\E[?7h:\
44         :UP=\E[%dA:\
45         :ac=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:\
46         :ae=^O:as=^N:bl=^G:cb=\E[1K:cd=\E[J:ce=\E[K:cl=\E[H\E[J:\
47         :cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:ct=\E[3g:do=^J:\
48         :eA=\E(B\E)0:ho=\E[H:kb=^H:kd=\EOB:ke=\E[?1l\E>:kl=\EOD:\
49         :kr=\EOC:ks=\E[?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:\
50         :me=\E[m\017:mr=\E[7m:nd=\E[C:rc=\E8:\
51         :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:sc=\E7:se=\E[m:\
52         :sf=^J:so=\E[7m:sr=\EM:st=\EH:ta=^I:ue=\E[m:up=\E[A:\
53         :us=\E[4m:tc=vt100+fnkeys:
54
55 vt100+fnkeys|dec vt100 numeric keypad:\
56         :k0=\EOy:k5=\EOt:k6=\EOu:k7=\EOv:k8=\EOl:k9=\EOw:k;=\EOx:\
57         :tc=vt100+pfkeys:
58
59 vt100+pfkeys|dec vt100 numeric keypad:\
60         :@8=\EOM:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:tc=vt100+keypad:
61
62 vt100+keypad|dec vt100 numeric keypad no fkeys:\
63         :K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:
64
65 */
66
67 /*
68 so the parser needs to be able to at least do
69 CTRL-G
70 CTRL-H
71 CTRL-I
72 CTRL-J
73 CTRL-M
74 CTRL-N
75 CTRL-O
76
77 ESC7
78 ESC8
79 ESCH
80 ESCM
81 ESC> 
82
83 ESC[%dA
84 ESC[%dB
85 ESC[%dC
86 ESC[%dD
87 ESC[H
88 ESC[%d;%dH
89 ESC[J
90 ESC[K
91 ESC[1K
92 ESC[L
93 ESC[M
94 ESC[P
95
96 ESC[3g
97 ESC[4h
98 ESC[4l
99 ESC[m 
100 ESC[1m
101 ESC[4m
102 ESC[5m
103 ESC[7m
104 ESC[%d;%dr
105
106 ESC(B
107 ESC)0
108
109 ESC[?3l 
110 ESC[?4l 
111 ESC[?5l
112 ESC[?7h
113 ESC[?7h
114 ESC[?7l
115 ESC[?8h
116
117 */
118
119 #include "project.h"
120
121
122 static inline int
123 csi_ender (int c)
124 {
125   if ((c >= 'a') && (c <= 'z'))
126     return 1;
127   if ((c >= 'A') && (c <= 'Z'))
128     return 1;
129   return 0;
130 }
131
132 static inline int
133 csi_starter (int c)
134 {
135   switch (c)
136     {
137     case '[':
138     case '(':
139     case ')':
140       return 1;
141     }
142   return 0;
143 }
144
145
146 void
147 vt102_cursor_normalize (VT102 * v, int do_wrapscroll, int use_margins)
148 {
149   int wrap = do_wrapscroll ? 1 : 0;
150   int scroll = do_wrapscroll ? 1 : 0;
151   CRT_Pos *top, *bottom;
152
153   if (use_margins)
154     {
155       top = &v->top_margin;
156       bottom = &v->bottom_margin;
157     }
158   else
159     {
160       top = &v->screen_start;
161       bottom = &v->screen_end;
162     }
163
164   if (v->pos.x < top->x)        /*don't wrap backwards */
165     v->pos.x = top->x;
166
167   if (v->pos.x > bottom->x)
168     {
169       if (wrap)
170         {
171           v->pos.x = top->x;
172           v->pos.y++;
173         }
174       else
175         {
176           v->pos.x = bottom->x;
177         }
178     }
179
180   if (v->pos.y < top->y)
181     v->pos.y = top->y;
182
183   if (v->pos.y > bottom->y)
184     {
185       if (scroll)
186         crt_scroll_up (&v->crt, *top, *bottom, 1);
187       v->pos.y = bottom->y;
188     }
189 }
190
191
192 void
193 vt102_cursor_motion (VT102 * v, int x, int y, int wrapscroll)
194 {
195   while (x > 0)
196     {
197       x--;
198       v->pos.x++;
199       vt102_cursor_normalize (v, wrapscroll, 1);
200     }
201
202   while (x < 0)
203     {
204       x++;
205       v->pos.x--;
206       vt102_cursor_normalize (v, wrapscroll, 1);
207     }
208
209   while (y > 0)
210     {
211       y--;
212       v->pos.y++;
213       vt102_cursor_normalize (v, wrapscroll, 1);
214     }
215
216   while (y < 0)
217     {
218       y++;
219       v->pos.y--;
220       vt102_cursor_normalize (v, wrapscroll, 1);
221     }
222 }
223
224 void
225 vt102_delete_from_line (VT102 * v, CRT_Pos p)
226 {
227   int n = v->bottom_margin.x - p.x;
228
229   if (n < 0)
230     return;
231
232   if (n)
233     {
234
235       memmove (&v->crt.screen[CRT_ADDR_POS (&p)],
236                &v->crt.screen[CRT_ADDR_POS (&p) + 1], sizeof (CRT_CA) * n);
237     }
238
239   v->crt.screen[CRT_ADDR (v->bottom_margin.x, p.y)].chr = ' ';
240 /*But not attr due to vt102 bug*/
241 }
242
243
244 void
245 vt102_parse_esc (VT102 * v, int c)
246 {
247   fprintf (stderr, "ESC 0%o(%c)\n", c, c);
248 }
249
250 void
251 vt102_parse_csi (VT102 * v, char *buf, int len)
252 {
253   char last;
254   char *ptr;
255   char *arg = buf + 1;
256   int narg;
257
258   buf[len] = 0;
259
260   last = buf[len - 1];
261 #if 0
262   buf[len - 1] = 0;
263 #endif
264
265   if (len>2)
266     {
267       narg = atoi (arg);
268     }
269   else
270     {
271       narg = 1;
272     }
273
274   switch (buf[0])
275     {
276     case '[':
277       switch (last)
278         {
279         case 'A':
280           vt102_cursor_motion (v, 0, -narg, 0);
281           break;
282         case 'B':
283           vt102_cursor_motion (v, 0, narg, 0);
284           break;
285         case 'C':
286           vt102_cursor_motion (v, narg, 0, 0);
287           break;
288         case 'D':
289           vt102_cursor_motion (v, -narg, 0, 0);
290           break;
291         case 'H':
292           v->pos.y = narg - 1;
293
294           ptr = index (arg, ';');
295           if (ptr)
296             v->pos.x = atoi (ptr + 1) - 1;
297           else
298             v->pos.x = 0;
299
300           vt102_cursor_normalize (v, 0, 0);
301           break;
302         case 'J':
303                 fprintf(stderr,"OCTOPUS %d\n",narg);
304           switch (narg)
305             {
306             case 1:
307               crt_erase (&v->crt, v->pos, v->screen_end, 1);
308               break;
309             case 2:
310               crt_erase (&v->crt, v->screen_start, v->screen_end, 1);
311               break;
312             }
313           break;
314         case 'K':
315           {
316             CRT_Pos ls = { 0, v->pos.y };
317             CRT_Pos le = { VT102_COLS - 1, v->pos.y };
318             if (len==2)
319               narg = 0;         /*Different default */
320
321             switch (narg)
322               {
323               case 0:
324                 fprintf(stderr,"FISH %d %d -> %d %d\n",
325                         v->pos.x,v->pos.y,
326                         le.x,le.y);
327                 crt_erase (&v->crt, v->pos, le, 1);
328                 break;
329               case 1:
330                 fprintf(stderr,"SOUP %d %d -> %d %d\n",
331                         ls.x,ls.y,
332                         v->pos.x,v->pos.y);
333                 crt_erase (&v->crt, ls, v->pos, 1);
334                 break;
335               case 2:
336                 fprintf(stderr,"TREE %d %d -> %d %d\n",
337                         ls.x,ls.y,
338                         le.x,le.y);
339                 crt_erase (&v->crt, ls, le, 1);
340                 break;
341               }
342           }
343           break;
344
345         case 'P':
346           while (narg--)
347             vt102_delete_from_line (v, v->pos);
348           break;
349         case 'L':
350           if ((v->pos.y >= v->top_margin.y)
351               && (v->pos.y <= v->bottom_margin.y))
352             {
353               while (narg--)
354                 crt_scroll_down (&v->crt, v->pos, v->bottom_margin, 1);
355             }
356           break;
357
358         case 'M':
359           if ((v->pos.y >= v->top_margin.y)
360               && (v->pos.y <= v->bottom_margin.y))
361             {
362               while (narg--)
363                 crt_scroll_up (&v->crt, v->pos, v->bottom_margin, 0);
364             }
365           break;
366
367           case 'g':
368           case 'h':
369         case 'l':
370           fprintf (stderr, "C: CSI %s buf[0]=%c\n", buf,buf[0]);
371                 break;
372
373         case 'm':
374         //horror of horrors parsing the ;
375         break;
376         case 'r':
377                 v->top_margin=v->screen_start;
378                 v->bottom_margin=v->screen_end;
379
380           if ((len>2) && (ptr=index(arg,';'))) {
381                 ptr++;
382                 v->top_margin.y=narg-1;
383                 v->bottom_margin.y=atoi(ptr)-1;
384           } 
385
386         if (v->top_margin.y<v->screen_start.y) v->top_margin.y=v->screen_start.y;
387         if (v->top_margin.y>v->screen_end.y) v->top_margin.y=v->screen_end.y;
388         if (v->bottom_margin.y<v->screen_start.y) v->bottom_margin.y=v->screen_start.y;
389         if (v->bottom_margin.y>v->screen_end.y) v->bottom_margin.y=v->screen_end.y;
390
391         fprintf(stderr,"D: %d %d\n",v->top_margin.y,v->bottom_margin.y);
392  
393          v->pos=v->top_margin;
394         break;
395
396         default:
397           fprintf (stderr, "A: CSI %s buf[0]=%c\n", buf,buf[0]);
398         }
399       break;
400     default:
401       fprintf (stderr, "B: CSI %s buf[0]=%c\n", buf,buf[0]);
402     }
403
404
405
406 }
407
408 void
409 vt102_status_line (VT102 * v, char *str)
410 {
411   int i = VT102_COLS;
412   CRT_CA *ca = &v->crt.screen[CRT_ADDR (VT102_STATUS_ROW, 0)];
413
414   while (i--)
415     {
416       ca->attr = CRT_ATTR_REVERSE;
417       ca->chr = *str;
418       if (*str)
419         str++;
420       ca++;
421     }
422
423 }
424
425
426 void
427 vt102_parse_char (VT102 * v, int c)
428 {
429   VT102_parser *p = &v->parser;
430
431 #if 0
432   fprintf (stderr, "%c pc %d %d %d   %d %d\n", c, c, p->in_csi, p->in_escape,
433            v->pos.x, v->pos.y);
434 #endif
435   if (p->in_csi)
436     {
437       p->csi_buf[p->csi_ptr++] = c;
438       if (csi_ender (c) || (p->csi_ptr == VT102_CSI_LEN))
439         {
440           vt102_parse_csi (v, p->csi_buf, p->csi_ptr);
441           p->in_csi = 0;
442         }
443     }
444   else if (p->in_escape)
445     {
446       if (csi_starter (c))
447         {
448           p->csi_ptr = 0;
449           p->csi_buf[p->csi_ptr++] = c;
450           p->in_csi++;
451           p->in_escape = 0;
452         }
453       else
454         {
455           p->in_escape = 0;
456           vt102_parse_esc (v, c);
457         }
458     }
459   else
460     {
461
462       switch (c)
463         {
464          /*NUL*/ case 0:
465          /*SOH*/ case 1:
466          /*STX*/ case 2:
467          /*ETX*/ case 3:
468          /*EOT*/ case 4:
469          /*ENQ*/ case 5:
470          /*ACK*/ case 6:
471          /*BEL*/ case 7:
472          /*BS*/ case 8:
473           vt102_cursor_motion (v, -1, 0, 1);
474           break;
475          /*HT*/ case 9:
476              v->pos.x+=8;
477              v->pos.x&=~7;
478                 vt102_cursor_normalize(v,1,1);
479           break;
480          /*LF*/ case 10:
481          /*VT*/ case 11:
482          /*FF*/ case 12:
483           vt102_cursor_motion (v, 0, 1, 1);
484           break;
485          /*CR*/ case 13:
486           v->pos.x = v->top_margin.x;
487           break;
488          /*SO*/ case 14:
489          /*SI*/ case 15:
490          /*DLE*/ case 16:
491         /*DC1 */ case 17:
492         /*DC2 */ case 18:
493         /*DC3 */ case 19:
494         /*DC4 */ case 20:
495          /*NAK*/ case 21:
496          /*SYN*/ case 22:
497          /*ETB*/ case 23:
498          /*CAN*/ case 24:
499          /*EM*/ case 25:
500          /*SUB*/ case 26:
501           break;
502          /*ESC*/ case 27:
503           p->in_escape++;
504           return;
505          /*FS*/ case 28:
506          /*GS*/ case 29:
507          /*RS*/ case 30:
508          /*US*/ case 31:
509          /*DEL*/ case 127:
510           break;
511         /*regular character */ default:
512           v->crt.screen[CRT_ADDR_POS (&v->pos)].chr = c;
513           v->crt.screen[CRT_ADDR_POS (&v->pos)].attr = v->attr;
514           vt102_cursor_motion (v, 1, 0, 1);
515         }
516     }
517
518   v->crt.pos = v->pos;
519
520   vt102_status_line (v, "VT102 foo bar baz I'm the urban spaceman baby");
521 }
522
523 void
524 vt102_parser_reset (VT102_parser * p)
525 {
526   p->in_csi = 0;
527   p->in_escape = 0;
528   p->csi_ptr = 0;
529 }
530
531 void
532 vt102_reset (VT102 * v)
533 {
534   VT102_parser *p = &v->parser;
535
536   vt102_parser_reset (p);
537   crt_cls (&v->crt);
538
539
540   v->screen_start.x = 0;
541   v->screen_start.y = 0;
542   v->screen_end.x = VT102_COLS - 1;
543   v->screen_end.y = VT102_ROWS - 1;
544
545   v->top_margin = v->screen_start;
546   v->bottom_margin = v->screen_end;
547
548   v->pos = v->screen_start;
549
550 }