chiark / gitweb /
4e951bba3c5a91081c2f34e5b831c0d133170b9c
[sympathy.git] / src / ansi.c
1 /*
2  * ansi.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.7  2008/02/06 20:26:57  james
14  * *** empty log message ***
15  *
16  * Revision 1.6  2008/02/06 17:53:28  james
17  * *** empty log message ***
18  *
19  * Revision 1.5  2008/02/06 15:53:22  james
20  * *** empty log message ***
21  *
22  * Revision 1.4  2008/02/04 20:23:55  james
23  * *** empty log message ***
24  *
25  * Revision 1.3  2008/02/04 05:45:55  james
26  * ::
27  *
28  * Revision 1.2  2008/02/04 02:05:06  james
29  * *** empty log message ***
30  *
31  * Revision 1.1  2008/02/03 23:31:25  james
32  * *** empty log message ***
33  *
34  */
35 #include "project.h"
36
37 void
38 ansi_write (ANSI * a, char *buf, int n)
39 {
40   write (a->fd, buf, n);
41 }
42
43 void
44 ansi_getsize (ANSI * a)
45 {
46   struct winsize sz = { 0 };
47   if (ioctl (a->fd, TIOCGWINSZ, &sz))
48     {
49       a->size.x = CRT_COLS;
50       a->size.y = CRT_ROWS;
51     }
52   else
53     {
54       a->size.x = sz.ws_col;
55       a->size.y = sz.ws_row;
56     }
57
58 }
59
60
61 void
62 ansi_move (ANSI * a, CRT_Pos p)
63 {
64   char buf[16];
65   int n;
66   int dx = p.x - a->pos.x;
67   int dy = p.y - a->pos.y;
68
69 //  a->pos.x = ANSI_INVAL;
70
71   if (a->pos.x != ANSI_INVAL)
72     {
73
74       if ((!dx) && (!dy))
75         return;
76
77       if (!dy)
78         {
79           if (dx == 1)
80             {
81               ansi_write (a, "\033[C", 3);
82             }
83           else if (dx == -1)
84             {
85               ansi_write (a, "\033[D", 3);
86             }
87           else
88             {
89               n = snprintf (buf, sizeof (buf), "\033[%dG", p.x + 1);
90               ansi_write (a, buf, n);
91             }
92         }
93       else if (!dx)
94         {
95           if (dy == -1)
96             {
97               ansi_write (a, "\033[A", 3);
98             }
99           else if (dy == 1)
100             {
101               ansi_write (a, "\033[B", 3);
102             }
103           else if (dy < 0)
104             {
105               n = snprintf (buf, sizeof (buf), "\033[%dA", -dy);
106               ansi_write (a, buf, n);
107             }
108           else
109             {
110               n = snprintf (buf, sizeof (buf), "\033[%dB", dy);
111               ansi_write (a, buf, n);
112             }
113         }
114       else if (!p.x)
115         {
116           if (dy == 1)
117             {
118               ansi_write (a, "\033[E", 3);
119             }
120           else if (dy == -1)
121             {
122               ansi_write (a, "\033[F", 3);
123             }
124           else if (dy > 0)
125             {
126               n = snprintf (buf, sizeof (buf), "\033[%dE", dy);
127               ansi_write (a, buf, n);
128             }
129           else
130             {
131               n = snprintf (buf, sizeof (buf), "\033[%dF", -dy);
132               ansi_write (a, buf, n);
133             }
134         }
135       else
136         {
137           n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1);
138           ansi_write (a, buf, n);
139         }
140     }
141   else
142     {
143       n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1);
144       ansi_write (a, buf, n);
145     }
146
147   a->pos = p;
148 }
149
150
151 void
152 ansi_showhide_cursor (ANSI * a, int hide)
153 {
154   if (a->hide_cursor == hide)
155     return;
156
157   if (hide)
158     {
159       ansi_write (a, "\033[?25l", 6);
160     }
161   else
162     {
163       ansi_write (a, "\033[?25h", 6);
164     }
165
166   a->hide_cursor = hide;
167 }
168
169
170 void
171 ansi_force_attr_normal (ANSI * a)
172 {
173   ansi_write (a, "\033[0m", 4);
174   a->attr = CRT_ATTR_NORMAL;
175 }
176
177 void
178 ansi_set_attr (ANSI * a, int attr)
179 {
180   int dif;
181
182   dif = attr ^ a->attr;
183
184   if (!dif)
185     return;
186
187   a->attr = attr;
188
189   if (attr == CRT_ATTR_NORMAL)
190     {
191       ansi_force_attr_normal (a);
192       return;
193     }
194
195   if (dif & CRT_ATTR_UNDERLINE)
196     {
197       if (attr & CRT_ATTR_UNDERLINE)
198         {
199           ansi_write (a, "\033[4m", 4);
200         }
201       else
202         {
203           ansi_write (a, "\033[24m", 5);
204         }
205     }
206   if (dif & CRT_ATTR_REVERSE)
207     {
208       if (attr & CRT_ATTR_REVERSE)
209         {
210           ansi_write (a, "\033[7m", 4);
211         }
212       else
213         {
214           ansi_write (a, "\033[27m", 5);
215         }
216     }
217   if (dif & CRT_ATTR_BOLD)
218     {
219       if (attr & CRT_ATTR_BOLD)
220         {
221           ansi_write (a, "\033[1m", 4);
222         }
223       else
224         {
225           ansi_write (a, "\033[21m", 5);
226           ansi_write (a, "\033[22m", 5);
227         }
228     }
229
230 }
231
232
233 void
234 ansi_render (ANSI * a, CRT_CA ca)
235 {
236   int dif;
237
238   if (ca.chr < 32)
239     ca.chr = ' ';
240   if (ca.chr > 126)
241     ca.chr = ' ';
242
243   ansi_set_attr (a, ca.attr);
244
245   ansi_write (a, &ca.chr, 1);
246
247   a->pos.x++;
248
249 /*Can't easily wrap round here as don't know size of destination screen*/
250 /*so invalidate the cached cursor position*/
251
252   if (a->pos.x >= CRT_COLS)
253     a->pos.x = ANSI_INVAL;
254
255 }
256
257 void
258 ansi_cls (ANSI * a)
259 {
260   CRT_Pos p = { 0 };
261
262   crt_cls (&a->crt);
263
264   ansi_force_attr_normal (a);
265   ansi_move (a, p);
266   ansi_write (a, "\033[2J", 4);
267 /*different emulators leave cursor in different places after cls differently*/
268   a->pos.x = ANSI_INVAL;
269 }
270
271
272 void
273 ansi_draw (ANSI * a, CRT * c)
274 {
275   CRT_Pos p;
276   int o;
277   int hidden_cursor = 0;
278
279   for (p.y = 0; p.y < CRT_ROWS; ++p.y)
280     {
281       if (p.y >= a->size.y)
282         continue;
283       o = CRT_ADDR (p.y, 0);
284       for (p.x = 0; p.x < CRT_COLS; ++p.x, ++o)
285         {
286           if (p.x >= a->size.x)
287             continue;
288           if (crt_ca_cmp (a->crt.screen[o], c->screen[o]))
289             {
290               ansi_showhide_cursor (a, 1);
291               a->crt.screen[o] = c->screen[o];
292
293               ansi_move (a, p);
294               ansi_render (a, a->crt.screen[o]);
295             }
296         }
297     }
298
299
300   if ((CRT_COLS > a->size.x) || (CRT_ROWS > a->size.y))
301     {
302       char msg[] = "Window is too small";
303       p.x = 0;
304       p.y = 0;
305
306       ansi_showhide_cursor (a, 1);
307       ansi_set_attr (a, CRT_ATTR_REVERSE);
308       ansi_move (a, p);
309
310       ansi_write (a, msg, sizeof (msg));
311       a->pos.x = ANSI_INVAL;
312     }
313
314
315   if ((c->pos.x >= a->size.x) || (c->pos.y >= a->size.y))
316     {
317       ansi_showhide_cursor (a, 1);
318       return;
319     }
320
321   a->crt.pos = c->pos;
322   ansi_move (a, a->crt.pos);
323
324   a->crt.hide_cursor = c->hide_cursor;
325   ansi_showhide_cursor (a, a->crt.hide_cursor);
326 }
327
328 void
329 ansi_reset (ANSI * a)
330 {
331 // FIXME: -- echos back crap?
332 //  ansi_write (a, "\033[c", 3);
333   ansi_getsize (a);
334
335   a->pos.x = ANSI_INVAL;
336   a->hide_cursor = ANSI_INVAL;
337
338   crt_reset (&a->crt);
339
340   ansi_cls (a);
341   ansi_draw (a, &a->crt);
342 }
343
344 void ansi_parse_char(ANSI *a,int c,VT102 *v)
345 {
346 vt102_send(v,c);
347 }
348
349 void ansi_parse(ANSI *a,char *buf,int len,VT102 *v)
350 {
351 while (len--) 
352 ansi_parse_char(a,*(buf++),v);
353 }
354
355 int ansi_dispatch(ANSI *a,VT102 *v)
356 {
357 char buf[1024];
358 int red;
359
360 red=read(a.fd,buf,sizeof(buf));
361 if (red<0) return -1;
362 if (!red) return -1;
363
364 ansi_parse(a,buf,red,v);
365
366 return 0;
367 }
368 int