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 38static const struct term_state default_state = { 39 .state = st_init, 40 .pvt = false, 41 .nparms = 0, 42 .xy = {0, 0}, 43 .cindex = 0, /* First color table entry */ 44 .vtgraphics = false, 45 .intensity = 1, 46 .underline = false, 47 .blink = false, 48 .reverse = false, 49 .fg = 7, 50 .bg = 0, 51 .autocr = true, /* Mimic \n -> \r\n conversion by default */ 52 .autowrap = true, /* Wrap lines by default */ 53 .saved_xy = {0, 0}, 54 .cursor = true, 55}; 56 57/* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */ 58static const char decvt_to_cp437[] = { 59 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 60 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304, 61 0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 62 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 63}; 64 65void __ansi_init(const struct term_info *ti) 66{ 67 memcpy(ti->ts, &default_state, sizeof default_state); 68} 69 70void __ansi_putchar(const struct term_info *ti, uint8_t ch) 71{ 72 const struct ansi_ops *op = ti->op; 73 struct term_state *st = ti->ts; 74 const int rows = ti->rows; 75 const int cols = ti->cols; 76 struct curxy xy = st->xy; 77 78 switch (st->state) { 79 case st_init: 80 switch (ch) { 81 case 1 ... 5: 82 st->state = st_tbl; 83 st->parms[0] = ch; 84 break; 85 case '\a': 86 op->beep(); 87 break; 88 case '\b': 89 if (xy.x > 0) 90 xy.x--; 91 break; 92 case '\t': 93 { 94 int nsp = 8 - (xy.x & 7); 95 while (nsp--) 96 __ansi_putchar(ti, ' '); 97 } 98 return; /* Cursor already updated */ 99 case '\n': 100 case '\v': 101 case '\f': 102 xy.y++; 103 if (st->autocr) 104 xy.x = 0; 105 break; 106 case '\r': 107 xy.x = 0; 108 break; 109 case 127: 110 /* Ignore delete */ 111 break; 112 case 14: 113 st->vtgraphics = 1; 114 break; 115 case 15: 116 st->vtgraphics = 0; 117 break; 118 case 27: 119 st->state = st_esc; 120 break; 121 default: 122 /* Print character */ 123 if (ch >= 32) { 124 if (st->vtgraphics && (ch & 0xe0) == 0x60) 125 ch = decvt_to_cp437[ch - 0x60]; 126 127 op->write_char(xy.x, xy.y, ch, st); 128 xy.x++; 129 } 130 break; 131 } 132 break; 133 134 case st_esc: 135 switch (ch) { 136 case '%': 137 case '(': 138 case ')': 139 case '#': 140 /* Ignore this plus the subsequent character, allows 141 compatibility with Linux sequence to set charset */ 142 break; 143 case '[': 144 st->state = st_csi; 145 st->nparms = 0; 146 st->pvt = false; 147 memset(st->parms, 0, sizeof st->parms); 148 break; 149 case 'c': 150 /* Reset terminal */ 151 memcpy(&st, &default_state, sizeof st); 152 op->erase(st, 0, 0, cols - 1, rows - 1); 153 xy.x = xy.y = 0; 154 st->state = st_init; 155 break; 156 default: 157 /* Ignore sequence */ 158 st->state = st_init; 159 break; 160 } 161 break; 162 163 case st_csi: 164 { 165 int p0 = st->parms[0] ? st->parms[0] : 1; 166 167 if (ch >= '0' && ch <= '9') { 168 st->parms[st->nparms] = st->parms[st->nparms] * 10 + (ch - '0'); 169 } else if (ch == ';') { 170 st->nparms++; 171 if (st->nparms >= ANSI_MAX_PARMS) 172 st->nparms = ANSI_MAX_PARMS - 1; 173 break; 174 } else if (ch == '?') { 175 st->pvt = true; 176 } else { 177 switch (ch) { 178 case 'A': 179 { 180 int y = xy.y - p0; 181 xy.y = (y < 0) ? 0 : y; 182 } 183 break; 184 case 'B': 185 { 186 int y = xy.y + p0; 187 xy.y = (y >= rows) ? rows - 1 : y; 188 } 189 break; 190 case 'C': 191 { 192 int x = xy.x + p0; 193 xy.x = (x >= cols) ? cols - 1 : x; 194 } 195 break; 196 case 'D': 197 { 198 int x = xy.x - p0; 199 xy.x = (x < 0) ? 0 : x; 200 } 201 break; 202 case 'E': 203 { 204 int y = xy.y + p0; 205 xy.y = (y >= rows) ? rows - 1 : y; 206 xy.x = 0; 207 } 208 break; 209 case 'F': 210 { 211 int y = xy.y - p0; 212 xy.y = (y < 0) ? 0 : y; 213 xy.x = 0; 214 } 215 break; 216 case 'G': 217 case '\'': 218 { 219 int x = st->parms[0] - 1; 220 xy.x = (x >= cols) ? cols - 1 : (x < 0) ? 0 : x; 221 } 222 break; 223 case 'H': 224 case 'f': 225 { 226 int y = st->parms[0] - 1; 227 int x = st->parms[1] - 1; 228 229 xy.x = (x >= cols) ? cols - 1 : (x < 0) ? 0 : x; 230 xy.y = (y >= rows) ? rows - 1 : (y < 0) ? 0 : y; 231 } 232 break; 233 case 'J': 234 { 235 switch (st->parms[0]) { 236 case 0: 237 op->erase(st, xy.x, xy.y, cols - 1, xy.y); 238 if (xy.y < rows - 1) 239 op->erase(st, 0, xy.y + 1, cols - 1, rows - 1); 240 break; 241 242 case 1: 243 if (xy.y > 0) 244 op->erase(st, 0, 0, cols - 1, xy.y - 1); 245 if (xy.y > 0) 246 op->erase(st, 0, xy.y, xy.x - 1, xy.y); 247 break; 248 249 case 2: 250 op->erase(st, 0, 0, cols - 1, rows - 1); 251 break; 252 253 default: 254 /* Ignore */ 255 break; 256 } 257 } 258 break; 259 case 'K': 260 { 261 switch (st->parms[0]) { 262 case 0: 263 op->erase(st, xy.x, xy.y, cols - 1, xy.y); 264 break; 265 266 case 1: 267 if (xy.x > 0) 268 op->erase(st, 0, xy.y, xy.x - 1, xy.y); 269 break; 270 271 case 2: 272 op->erase(st, 0, xy.y, cols - 1, xy.y); 273 break; 274 275 default: 276 /* Ignore */ 277 break; 278 } 279 } 280 break; 281 case 'h': 282 case 'l': 283 { 284 bool set = (ch == 'h'); 285 switch (st->parms[0]) { 286 case 7: /* DECAWM */ 287 st->autowrap = set; 288 break; 289 case 20: /* LNM */ 290 st->autocr = set; 291 break; 292 case 25: /* DECTECM */ 293 st->cursor = set; 294 op->showcursor(st); 295 break; 296 default: 297 /* Ignore */ 298 break; 299 } 300 break; 301 } 302 case 'm': 303 { 304 static const int ansi2pc[8] = 305 { 0, 4, 2, 6, 1, 5, 3, 7 }; 306 307 int i; 308 for (i = 0; i <= st->nparms; i++) { 309 int a = st->parms[i]; 310 switch (a) { 311 case 0: 312 st->fg = 7; 313 st->bg = 0; 314 st->intensity = 1; 315 st->underline = 0; 316 st->blink = 0; 317 st->reverse = 0; 318 break; 319 case 1: 320 st->intensity = 2; 321 break; 322 case 2: 323 st->intensity = 0; 324 break; 325 case 4: 326 st->underline = 1; 327 break; 328 case 5: 329 st->blink = 1; 330 break; 331 case 7: 332 st->reverse = 1; 333 break; 334 case 21: 335 case 22: 336 st->intensity = 1; 337 break; 338 case 24: 339 st->underline = 0; 340 break; 341 case 25: 342 st->blink = 0; 343 break; 344 case 27: 345 st->reverse = 0; 346 break; 347 case 30 ... 37: 348 st->fg = ansi2pc[a - 30]; 349 break; 350 case 38: 351 st->fg = 7; 352 st->underline = 1; 353 break; 354 case 39: 355 st->fg = 7; 356 st->underline = 0; 357 break; 358 case 40 ... 47: 359 st->bg = ansi2pc[a - 40]; 360 break; 361 case 49: 362 st->bg = 7; 363 break; 364 default: 365 /* Do nothing */ 366 break; 367 } 368 } 369 } 370 break; 371 case 's': 372 st->saved_xy = xy; 373 break; 374 case 'u': 375 xy = st->saved_xy; 376 break; 377 default: /* Includes CAN and SUB */ 378 break; /* Drop unknown sequence */ 379 } 380 st->state = st_init; 381 } 382 } 383 break; 384 385 case st_tbl: 386 st->parms[1] = 0; 387 if (ch == '#') 388 st->state = st_tblc; 389 else 390 st->state = st_init; 391 break; 392 393 case st_tblc: 394 { 395 unsigned int n = (unsigned char)ch - '0'; 396 const char *p; 397 398 if (n < 10) { 399 st->parms[1] = st->parms[1] * 10 + n; 400 401 if (!--st->parms[0]) { 402 if (st->parms[1] < console_color_table_size) { 403 /* Set the color table index */ 404 st->cindex = st->parms[1]; 405 406 /* See if there are any other attributes we care about */ 407 p = console_color_table[st->parms[1]].ansi; 408 if (p) { 409 st->state = st_esc; 410 __ansi_putchar(ti, '['); 411 __ansi_putchar(ti, '0'); 412 __ansi_putchar(ti, ';'); 413 while (*p) 414 __ansi_putchar(ti, *p++); 415 __ansi_putchar(ti, 'm'); 416 } 417 } 418 st->state = st_init; 419 } 420 } else { 421 st->state = st_init; 422 } 423 } 424 break; 425 } 426 427 /* If we fell off the end of the screen, adjust */ 428 if (xy.x >= cols) { 429 if (st->autowrap) { 430 xy.x = 0; 431 xy.y++; 432 } else { 433 xy.x = cols - 1; 434 } 435 } 436 while (xy.y >= rows) { 437 xy.y--; 438 op->scroll_up(st); 439 } 440 441 /* Update cursor position */ 442 op->set_cursor(xy.x, xy.y, st->cursor); 443 st->xy = xy; 444} 445