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