chiark / gitweb /
5d6105eb83437fb366cd78d0db48a60a70219a05
[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.1  2008/02/03 23:31:25  james
14  * *** empty log message ***
15  *
16  */
17
18 void
19 ansi_write (ANSI * a, char *buf, int n)
20 {
21   write (a->fd, buf, n);
22 }
23
24
25
26 void
27 ansi_move (ANSI * a, CRT_Pos p)
28 {
29   char buf[16];
30   int n;
31   int dx = a->pos.x - p.x;
32   int dy = a->pos.y - p.y;
33
34
35   if (a->pos.x != ANSI_INVAL)
36     {
37
38       if ((!dx) && (!dy))
39         return;
40
41       if (!dy)
42         {
43           if (dx == 1)
44             {
45               ansi_write (a, "\033[C", 3);
46             }
47           else if (dx == -1)
48             {
49               ansi_write (a, "\033[D", 3);
50             }
51           else
52             {
53               n = snprintf (buf, sizeof (buf), "\033[%dG", p.x + 1);
54               ansi_write (a, buf, n);
55             }
56         }
57       else if (!dx)
58         {
59           if (dy == -1)
60             {
61               ansi_write (a, "\033[A", 3);
62             }
63           else if (dy == 1)
64             {
65               ansi_write (a, "\033[B", 3);
66             }
67           else if (dy < 0)
68             {
69               n = snprintf (buf, sizeof (buf), "\033[%dA", -dy);
70               ansi_write (a, buf, n);
71             }
72           else
73             {
74               n = snprintf (buf, sizeof (buf), "\033[%dB", dy);
75               ansi_write (a, buf, n);
76             }
77         }
78       else if (!p.x)
79         {
80           if (dy == 1)
81             {
82               ansi_write (a, "\033[E", 3);
83             }
84           else if (dy == -1)
85             {
86               ansi_write (a, "\033[F", 3);
87             }
88           else if (dy > 0)
89             {
90               n = snprintf (buf, sizeof (buf), "\033[%dE", -dy);
91               ansi_write (a, buf, n);
92             }
93           else
94             {
95               n = snprintf (buf, sizeof (buf), "\033[%dF", dy);
96               ansi_write (a, buf, n);
97             }
98         }
99       else
100         {
101           n = snprintf (buf, sizeof (buf), "\033[%d;%dHF", p.y + 1, p.x + 1);
102           ansi_write (a, buf, n);
103         }
104     }
105   else
106     {
107       n = snprintf (buf, sizeof (buf), "\033[%d;%dHF", p.y + 1, p.x + 1);
108       ansi_write (a, buf, n);
109     }
110
111   a->pos = p;
112 }
113
114
115 void
116 ansi_showhide_cursor (ANSI * a, int hide)
117 {
118   if (a->hide_cursor == hide)
119     return;
120
121   if (hide)
122     {
123       ansi_write (a, "\033[?25h", 6);
124     }
125   else
126     {
127       ansi_write (a, "\033[?25l", 6);
128     }
129
130   a->hide_cursor = hide;
131 }
132
133
134 void ansi_force_attr_normal(ANSI *a)
135 {
136   ansi_write (a, "\033[0m", 4);
137   a->attr=CRT_ATTR_NORMAL;
138 }
139
140 void
141 ansi_set_attr (ANSI * a, int attr)
142 {
143
144   dif = attr ^ a->attr;
145
146   if (!dif)
147     return;
148
149   if (attr == ATTR_NORMAL)
150     {
151         ansi_force_attr_normal(a);
152         return;
153     }
154
155       if (dif & CRT_ATTR_UNDERLINE)
156         {
157           if (attr & CRT_ATTR_UNDERLINE)
158             {
159               ansi_write (a, "\033[4m", 4);
160             }
161           else
162             {
163               ansi_write (a, "\033[24m", 5);
164             }
165         }
166       if (dif & CRT_ATTR_REVERSE)
167         {
168           if (attr & CRT_ATTR_REVERSE)
169             {
170               ansi_write (a, "\033[7m", 4);
171             }
172           else
173             {
174               ansi_write (a, "\033[27m", 5);
175             }
176         }
177       if (dif & CRT_ATTR_BOLD)
178         {
179           if (attr & CRT_ATTR_REVERSE)
180             {
181               ansi_write (a, "\033[1m", 4);
182             }
183           else
184             {
185               ansi_write (a, "\033[22m", 5);
186             }
187         }
188 }
189
190
191 void
192 ansi_render (ANSI * a, CRT_CA ca)
193 {
194   int dif;
195
196   if (ca.chr < 32)
197     ca.chr = ' ';
198   if (ca.chr > 126)
199     ca.chr = ' ';
200
201   ansi_set_attr (a, ca.attr);
202
203   ansi_write (a, &ca.chr, 1);
204
205   a->pos.x++;
206
207 /*Can't easily wrap round here as don't know size of destination screen*/
208 /*so invalidate the cached cursor position*/
209
210   if (a->pos.x >= CRT_COLS)
211     a->pos.x = ANSI_INVAL;
212
213 }
214
215 void
216 ansi_cls (ANSI * a)
217 {
218   CRT_Pos p = { 0 };
219
220   crt_cls (&a->crt);
221   ansi_force_attr_normal(a);
222   ansi_move (a, p);
223   ansi_write (a, "\033[2J", 4);
224 /*different emulators leave cursor in different places after cls differently*/
225   a->pos.x = ANSI_INVAL;
226 }
227
228
229 void
230 ansi_draw (ANSI * a, CRT * c)
231 {
232   CRT_Pos p;
233   int o;
234
235   ansi_showhide_cursor (a, 1);
236
237   for (p.y = 0; p.y < CRT_ROWS; ++p.y)
238     {
239       if (p.y >= a->size.y)
240         continue;
241       o = CRT_ADDR (r, 0);
242       for (p.x = 0; p.x < CRT_COLS; ++p.x, ++o)
243         {
244           if (p.x >= a->size.x)
245             continue;
246           if (crt_ca_cmp (a->crt.screen[p], c->screen[p]))
247             {
248               a->crt.screen[p] = c->screen[p];
249
250               ansi_move (a, p);
251               ansi_render (a, a->crt.screen[p]);
252             }
253         }
254     }
255
256   a->crt.pos = c->pos;
257   ansi_move (a, a->crt.pos);
258
259   a->crt.hide_cursor = c->hide_cursor;
260   ansi_showhide_cursor (a, ci->crt.hide_cursor);
261 }
262
263 void
264 ansi_reset (ANSI * a)
265 {
266   ansi_write (a, "\033[c", 3);
267
268   a->pos.x = ANSI_INVAL;
269   a->hide_cursor = ANSI_INVAL;
270
271   crt_reset (&a->crt);
272
273   ansi_cls (a);
274   ansi_draw (a, &a->crt);
275 }