Add back spaces around ellipses in case statements
[people/sha0/syslinux.git] / com32 / lib / sys / ansi.c
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
4  *
5  *   Permission is hereby granted, free of charge, to any person
6  *   obtaining a copy of this software and associated documentation
7  *   files (the "Software"), to deal in the Software without
8  *   restriction, including without limitation the rights to use,
9  *   copy, modify, merge, publish, distribute, sublicense, and/or
10  *   sell copies of the Software, and to permit persons to whom
11  *   the Software is furnished to do so, subject to the following
12  *   conditions:
13  *
14  *   The above copyright notice and this permission notice shall
15  *   be included in all copies or substantial portions of the Software.
16  *
17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  *   OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * ----------------------------------------------------------------------- */
27
28 /*
29  * ansi.c
30  *
31  * ANSI character code engine
32  */
33
34 #include <string.h>
35 #include <colortbl.h>
36 #include "ansi.h"
37
38 static const struct term_state default_state = {
39     .xy = {0, 0},
40     .cindex = 0,                /* First color table entry */
41     .vtgraphics = 0,
42     .intensity = 1,
43     .underline = 0,
44     .blink = 0,
45     .reverse = 0,
46     .fg = 7,
47     .bg = 0,
48     .autocr = 1,                /* Mimic \n -> \r\n conversion by default */
49     .saved_xy = {0, 0},
50     .cursor = 1,
51     .state = st_init,
52     .pvt = 0,
53     .nparms = 0,
54 };
55
56 /* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
57 static const char decvt_to_cp437[] = {
58     0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361,
59     0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
60     0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302,
61     0263, 0363, 0362, 0343, 0330, 0234, 0007, 00
62 };
63
64 void __ansi_init(const struct term_info *ti)
65 {
66     memcpy(ti->ts, &default_state, sizeof default_state);
67 }
68
69 void __ansi_putchar(const struct term_info *ti, uint8_t ch)
70 {
71     const struct ansi_ops *op = ti->op;
72     struct term_state *st = ti->ts;
73     const int rows = ti->rows;
74     const int cols = ti->cols;
75     struct curxy xy = st->xy;
76
77     switch (st->state) {
78     case st_init:
79         switch (ch) {
80         case 1 ... 5:
81             st->state = st_tbl;
82             st->parms[0] = ch;
83             break;
84         case '\a':
85             op->beep();
86             break;
87         case '\b':
88             if (xy.x > 0)
89                 xy.x--;
90             break;
91         case '\t':
92             {
93                 int nsp = 8 - (xy.x & 7);
94                 while (nsp--)
95                     __ansi_putchar(ti, ' ');
96             }
97             return;             /* Cursor already updated */
98         case '\n':
99         case '\v':
100         case '\f':
101             xy.y++;
102             if (st->autocr)
103                 xy.x = 0;
104             break;
105         case '\r':
106             xy.x = 0;
107             break;
108         case 127:
109             /* Ignore delete */
110             break;
111         case 14:
112             st->vtgraphics = 1;
113             break;
114         case 15:
115             st->vtgraphics = 0;
116             break;
117         case 27:
118             st->state = st_esc;
119             break;
120         default:
121             /* Print character */
122             if (ch >= 32) {
123                 if (st->vtgraphics && (ch & 0xe0) == 0x60)
124                     ch = decvt_to_cp437[ch - 0x60];
125
126                 op->write_char(xy.x, xy.y, ch, st);
127                 xy.x++;
128             }
129             break;
130         }
131         break;
132
133     case st_esc:
134         switch (ch) {
135         case '%':
136         case '(':
137         case ')':
138         case '#':
139             /* Ignore this plus the subsequent character, allows
140                compatibility with Linux sequence to set charset */
141             break;
142         case '[':
143             st->state = st_csi;
144             st->nparms = st->pvt = 0;
145             memset(st->parms, 0, sizeof st->parms);
146             break;
147         case 'c':
148             /* Reset terminal */
149             memcpy(&st, &default_state, sizeof st);
150             op->erase(st, 0, 0, cols - 1, rows - 1);
151             xy.x = xy.y = 0;
152             st->state = st_init;
153             break;
154         default:
155             /* Ignore sequence */
156             st->state = st_init;
157             break;
158         }
159         break;
160
161     case st_csi:
162         {
163             int p0 = st->parms[0] ? st->parms[0] : 1;
164
165             if (ch >= '0' && ch <= '9') {
166                 st->parms[st->nparms] = st->parms[st->nparms] * 10 + (ch - '0');
167             } else if (ch == ';') {
168                 st->nparms++;
169                 if (st->nparms >= ANSI_MAX_PARMS)
170                     st->nparms = ANSI_MAX_PARMS - 1;
171                 break;
172             } else if (ch == '?') {
173                 st->pvt = 1;
174             } else {
175                 switch (ch) {
176                 case 'A':
177                     {
178                         int y = xy.y - p0;
179                         xy.y = (y < 0) ? 0 : y;
180                     }
181                     break;
182                 case 'B':
183                     {
184                         int y = xy.y + p0;
185                         xy.y = (y >= rows) ? rows - 1 : y;
186                     }
187                     break;
188                 case 'C':
189                     {
190                         int x = xy.x + p0;
191                         xy.x = (x >= cols) ? cols - 1 : x;
192                     }
193                     break;
194                 case 'D':
195                     {
196                         int x = xy.x - p0;
197                         xy.x = (x < 0) ? 0 : x;
198                     }
199                     break;
200                 case 'E':
201                     {
202                         int y = xy.y + p0;
203                         xy.y = (y >= rows) ? rows - 1 : y;
204                         xy.x = 0;
205                     }
206                     break;
207                 case 'F':
208                     {
209                         int y = xy.y - p0;
210                         xy.y = (y < 0) ? 0 : y;
211                         xy.x = 0;
212                     }
213                     break;
214                 case 'G':
215                 case '\'':
216                     {
217                         int x = st->parms[0] - 1;
218                         xy.x = (x >= cols) ? cols - 1 : (x < 0) ? 0 : x;
219                     }
220                     break;
221                 case 'H':
222                 case 'f':
223                     {
224                         int y = st->parms[0] - 1;
225                         int x = st->parms[1] - 1;
226
227                         xy.x = (x >= cols) ? cols - 1 : (x < 0) ? 0 : x;
228                         xy.y = (y >= rows) ? rows - 1 : (y < 0) ? 0 : y;
229                     }
230                     break;
231                 case 'J':
232                     {
233                         switch (st->parms[0]) {
234                         case 0:
235                             op->erase(st, xy.x, xy.y, cols - 1, xy.y);
236                             if (xy.y < rows - 1)
237                                 op->erase(st, 0, xy.y + 1, cols - 1, rows - 1);
238                             break;
239
240                         case 1:
241                             if (xy.y > 0)
242                                 op->erase(st, 0, 0, cols - 1, xy.y - 1);
243                             if (xy.y > 0)
244                                 op->erase(st, 0, xy.y, xy.x - 1, xy.y);
245                             break;
246
247                         case 2:
248                             op->erase(st, 0, 0, cols - 1, rows - 1);
249                             break;
250
251                         default:
252                             /* Ignore */
253                             break;
254                         }
255                     }
256                     break;
257                 case 'K':
258                     {
259                         switch (st->parms[0]) {
260                         case 0:
261                             op->erase(st, xy.x, xy.y, cols - 1, xy.y);
262                             break;
263
264                         case 1:
265                             if (xy.x > 0)
266                                 op->erase(st, 0, xy.y, xy.x - 1, xy.y);
267                             break;
268
269                         case 2:
270                             op->erase(st, 0, xy.y, cols - 1, xy.y);
271                             break;
272
273                         default:
274                             /* Ignore */
275                             break;
276                         }
277                     }
278                     break;
279                 case 'h':
280                 case 'l':
281                     {
282                         int set = (ch == 'h');
283                         switch (st->parms[0]) {
284                         case 20:
285                             st->autocr = set;
286                             break;
287                         case 25:
288                             st->cursor = set;
289                             op->showcursor(st);
290                             break;
291                         default:
292                             /* Ignore */
293                             break;
294                         }
295                     }
296                     break;
297                 case 'm':
298                     {
299                         static const int ansi2pc[8] =
300                             { 0, 4, 2, 6, 1, 5, 3, 7 };
301
302                         int i;
303                         for (i = 0; i <= st->nparms; i++) {
304                             int a = st->parms[i];
305                             switch (a) {
306                             case 0:
307                                 st->fg = 7;
308                                 st->bg = 0;
309                                 st->intensity = 1;
310                                 st->underline = 0;
311                                 st->blink = 0;
312                                 st->reverse = 0;
313                                 break;
314                             case 1:
315                                 st->intensity = 2;
316                                 break;
317                             case 2:
318                                 st->intensity = 0;
319                                 break;
320                             case 4:
321                                 st->underline = 1;
322                                 break;
323                             case 5:
324                                 st->blink = 1;
325                                 break;
326                             case 7:
327                                 st->reverse = 1;
328                                 break;
329                             case 21:
330                             case 22:
331                                 st->intensity = 1;
332                                 break;
333                             case 24:
334                                 st->underline = 0;
335                                 break;
336                             case 25:
337                                 st->blink = 0;
338                                 break;
339                             case 27:
340                                 st->reverse = 0;
341                                 break;
342                             case 30 ... 37:
343                                 st->fg = ansi2pc[a - 30];
344                                 break;
345                             case 38:
346                                 st->fg = 7;
347                                 st->underline = 1;
348                                 break;
349                             case 39:
350                                 st->fg = 7;
351                                 st->underline = 0;
352                                 break;
353                             case 40 ... 47:
354                                 st->bg = ansi2pc[a - 40];
355                                 break;
356                             case 49:
357                                 st->bg = 7;
358                                 break;
359                             default:
360                                 /* Do nothing */
361                                 break;
362                             }
363                         }
364                     }
365                     break;
366                 case 's':
367                     st->saved_xy = xy;
368                     break;
369                 case 'u':
370                     xy = st->saved_xy;
371                     break;
372                 default:        /* Includes CAN and SUB */
373                     break;      /* Drop unknown sequence */
374                 }
375                 st->state = st_init;
376             }
377         }
378         break;
379
380     case st_tbl:
381         st->parms[1] = 0;
382         if (ch == '#')
383             st->state = st_tblc;
384         else
385             st->state = st_init;
386         break;
387
388     case st_tblc:
389         {
390             unsigned int n = (unsigned char)ch - '0';
391             const char *p;
392
393             if (n < 10) {
394                 st->parms[1] = st->parms[1] * 10 + n;
395
396                 if (!--st->parms[0]) {
397                     if (st->parms[1] < console_color_table_size) {
398                         /* Set the color table index */
399                         st->cindex = st->parms[1];
400
401                         /* See if there are any other attributes we care about */
402                         p = console_color_table[st->parms[1]].ansi;
403                         if (p) {
404                             st->state = st_esc;
405                             __ansi_putchar(ti, '[');
406                             __ansi_putchar(ti, '0');
407                             __ansi_putchar(ti, ';');
408                             while (*p)
409                                 __ansi_putchar(ti, *p++);
410                             __ansi_putchar(ti, 'm');
411                         }
412                     }
413                     st->state = st_init;
414                 }
415             } else {
416                 st->state = st_init;
417             }
418         }
419         break;
420     }
421
422     /* If we fell off the end of the screen, adjust */
423     if (xy.x >= cols) {
424         xy.x = 0;
425         xy.y++;
426     }
427     while (xy.y >= rows) {
428         xy.y--;
429         op->scroll_up(st);
430     }
431
432     /* Update cursor position */
433     op->set_cursor(xy.x, xy.y, st->cursor);
434     st->xy = xy;
435 }