Changeset 4074 for neercs/trunk/src/term.c
- Timestamp:
- Nov 30, 2009, 11:26:50 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
neercs/trunk/src/term.c
r4063 r4074 28 28 29 29 #include <caca.h> 30 #include <caca.h>31 30 32 31 #include "neercs.h" 33 32 34 /* DEC ACS with common extensions */35 static uint32_t dec_acs(uint32_t uc)36 {37 switch (uc)38 {39 case '+':40 return 0x2192; /* RIGHTWARDS ARROW */41 case ',':42 return 0x2190; /* LEFTWARDS ARROW */43 case '-':44 return 0x2191; /* UPWARDS ARROW */45 case '.':46 return 0x2193; /* DOWNWARDS ARROW */47 case '0':48 return 0x25AE; /* BLACK VERTICAL RECTANGLE */49 case '_':50 return 0x25AE; /* BLACK VERTICAL RECTANGLE */51 case '`':52 return 0x25C6; /* BLACK DIAMOND */53 case 'a':54 return 0x2592; /* MEDIUM SHADE */55 case 'b':56 return 0x2409; /* SYMBOL FOR HORIZONTAL TABULATION */57 case 'c':58 return 0x240C; /* SYMBOL FOR FORM FEED */59 case 'd':60 return 0x240D; /* SYMBOL FOR CARRIAGE RETURN */61 case 'e':62 return 0x240A; /* SYMBOL FOR LINE FEED */63 case 'f':64 return 0x00B0; /* DEGREE SIGN */65 case 'g':66 return 0x00B1; /* PLUS-MINUS SIGN */67 case 'h':68 return 0x2424; /* SYMBOL FOR NEWLINE */69 case 'i':70 return 0x240B; /* SYMBOL FOR VERTICAL TABULATION */71 case 'j':72 return 0x2518; /* BOX DRAWINGS LIGHT UP AND LEFT */73 case 'k':74 return 0x2510; /* BOX DRAWINGS LIGHT DOWN AND LEFT */75 case 'l':76 return 0x250C; /* BOX DRAWINGS LIGHT DOWN AND RIGHT */77 case 'm':78 return 0x2514; /* BOX DRAWINGS LIGHT UP AND RIGHT */79 case 'n':80 return 0x253C; /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */81 case 'o':82 return 0x23BA; /* HORIZONTAL SCAN LINE-1 */83 case 'p':84 return 0x23BB; /* HORIZONTAL SCAN LINE-3 */85 case 'q':86 return 0x2500; /* BOX DRAWINGS LIGHT HORIZONTAL */87 case 'r':88 return 0x23BC; /* HORIZONTAL SCAN LINE-7 */89 case 's':90 return 0x23BD; /* HORIZONTAL SCAN LINE-9 */91 case 't':92 return 0x251C; /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */93 case 'u':94 return 0x2524; /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */95 case 'v':96 return 0x2534; /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */97 case 'w':98 return 0x252C; /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */99 case 'x':100 return 0x2502; /* BOX DRAWINGS LIGHT VERTICAL */101 case 'y':102 return 0x2264; /* LESS-THAN OR EQUAL TO */103 case 'z':104 return 0x2265; /* GREATER-THAN OR EQUAL TO */105 case '{':106 return 0x03C0; /* GREEK SMALL LETTER PI */107 case '|':108 return 0x2260; /* NOT EQUAL TO */109 case '}':110 return 0x00A3; /* POUND SIGN */111 case '~':112 return 0x00B7; /* MIDDLE DOT */113 default:114 return uc;115 }116 };117 118 static void reset_conv_state(struct screen *);119 120 #define LITERAL2CHAR(i0,i1) (((i0) << 8) | (i1))121 122 #define LITERAL3CHAR(i0,i1,i2) LITERAL2CHAR(LITERAL2CHAR(i0, i1), i2)123 124 static void ansi_parse_grcm(struct screen *,125 unsigned int, unsigned int const *);126 127 static int handle_single_char(unsigned char c, int *x, int *y,128 struct screen_list *screen_list,129 struct screen *sc);130 131 static int handle_single_char(unsigned char c, int *x, int *y,132 struct screen_list *screen_list,133 struct screen *sc)134 {135 if (c == '\r')136 {137 *x = 0;138 }139 140 else if (c == '\n')141 {142 *x = 0;143 *y = *y + 1;144 }145 else if (c == '\a')146 {147 if (!sc->bell)148 screen_list->in_bell = 10;149 sc->bell = 1;150 }151 152 else if (c == '\t')153 {154 *x = (*x + 7) & ~7;155 }156 157 else if (c == '\x08')158 {159 if (*x > 0)160 *x = *x - 1;161 }162 else if (c == '\x0b')163 {164 /* Vertical tab */165 /* Not sure about the real meaning of it, just y++ for now */166 if (*y < caca_get_canvas_height(sc->cv))167 *y = *y + 1;168 }169 else if (c == '\x0e')170 {171 /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: invokes172 the G1 character set. */173 sc->conv_state.glr[0] = 1;174 }175 176 else if (c == '\x0f')177 {178 /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes the179 G0 character set. */180 sc->conv_state.glr[0] = 0;181 }182 else183 {184 return 1;185 }186 return 0;187 188 }189 190 long int import_term(struct screen_list *screen_list, struct screen *sc,191 void const *data, unsigned int size)192 {193 unsigned char const *buffer = (unsigned char const *)data;194 unsigned int i, j, k, skip, dummy = 0;195 unsigned int width, height, top, bottom;196 uint32_t savedattr;197 int x = 0, y = 0, save_x = 0, save_y = 0;198 char b[100];199 200 debug("ansi : import_term\n");201 202 width = caca_get_canvas_width(sc->cv);203 height = caca_get_canvas_height(sc->cv);204 x = caca_get_cursor_x(sc->cv);205 y = caca_get_cursor_y(sc->cv);206 top = 1;207 bottom = height;208 209 if (!sc->init)210 {211 sc->dfg = CACA_LIGHTGRAY;212 sc->dbg = CACA_BLACK;213 214 caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg);215 sc->clearattr = caca_get_attr(sc->cv, -1, -1);216 217 ansi_parse_grcm(sc, 1, &dummy);218 219 reset_conv_state(sc);220 221 sc->init = 1;222 }223 224 for (i = 0; i < size; i += skip)225 {226 uint32_t ch = 0;227 int wch = 0;228 229 skip = 1;230 231 /* Control codes (ASCII < \x20) */232 if (!handle_single_char(buffer[i], &x, &y, screen_list, sc))233 {234 }235 236 /* If there are not enough characters to parse the escape sequence,237 wait until the next try. We require 3. */238 239 else if (buffer[i] == '\033' && i + 2 >= size)240 break;241 242 /* Single Shift Select of G2 Character Set (SS2: 0x8e): affects next243 character only */244 else if (buffer[i] == '\033' && buffer[i + 1] == 'N')245 {246 sc->conv_state.ss = 2;247 skip += 1;248 }249 /* Reverse Index (RI) go up one line, reverse scroll if necessary */250 else if (buffer[i] == '\033' && buffer[i + 1] == 'M')251 {252 /* FIXME : not sure about the meaning of 'go up one line' and 'if253 necessary' words. Implemented as a scroller only. */254 for (j = bottom - 1; j > top; j--)255 {256 for (k = 0; k < width; k++)257 {258 caca_put_char(sc->cv, k, j,259 caca_get_char(sc->cv, k, j - 1));260 caca_put_attr(sc->cv, k, j,261 caca_get_attr(sc->cv, k, j - 1));262 }263 }264 caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' ');265 skip += 1;266 }267 268 /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next269 character only */270 else if (buffer[i] == '\033' && buffer[i + 1] == 'O')271 {272 sc->conv_state.ss = 3;273 skip += 1;274 }275 276 /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */277 else if (buffer[i] == '\033' && buffer[i + 1] == 'n')278 {279 sc->conv_state.glr[0] = 2;280 skip += 1;281 }282 283 /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988284 */285 else if (buffer[i] == '\033' && buffer[i + 1] == 'o')286 {287 sc->conv_state.glr[0] = 3;288 skip += 1;289 }290 291 /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */292 else if (buffer[i] == '\033' && buffer[i + 1] == 'c')293 {294 sc->dfg = CACA_DEFAULT;295 sc->dbg = CACA_DEFAULT;296 297 caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg);298 sc->clearattr = caca_get_attr(sc->cv, -1, -1);299 ansi_parse_grcm(sc, 1, &dummy);300 301 reset_conv_state(sc);302 skip += 1;303 }304 305 /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992306 (ISO IR 189) */307 else if (buffer[i] == '\033' && buffer[i + 1] == 'd')308 {309 reset_conv_state(sc);310 skip += 1;311 }312 313 /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form314 from ISO 2022:1986] */315 else if (buffer[i] == '\033' && buffer[i + 1] == '$'316 && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C'))317 {318 sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]);319 skip += 2;320 }321 322 /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish323 these */324 else if (buffer[i] == '\033' && buffer[i + 1] == '$'325 && (i + 3 >= size))326 break;327 328 /* GZD4 G0-Designator, 94 chars */329 else if (buffer[i] == '\033' && buffer[i + 1] == '(')330 {331 sc->conv_state.gn[0] = buffer[i + 2];332 skip += 2;333 }334 335 /* G1D4 G1-Designator, 94 chars */336 else if (buffer[i] == '\033' && buffer[i + 1] == ')')337 {338 sc->conv_state.gn[1] = buffer[i + 2];339 skip += 2;340 }341 342 /* G2D4 G2-Designator, 94 chars */343 else if (buffer[i] == '\033' && buffer[i + 1] == '*')344 {345 sc->conv_state.gn[2] = buffer[i + 2];346 skip += 2;347 }348 349 /* G3D4 G3-Designator, 94 chars */350 else if (buffer[i] == '\033' && buffer[i + 1] == '+')351 {352 sc->conv_state.gn[3] = buffer[i + 2];353 skip += 2;354 }355 356 /* G2D6 G2-Designator, 96 chars */357 else if (buffer[i] == '\033' && buffer[i + 1] == '.')358 {359 sc->conv_state.gn[2] = LITERAL2CHAR('.', buffer[i + 2]);360 skip += 2;361 }362 363 /* G3D6 G3-Designator, 96 chars */364 else if (buffer[i] == '\033' && buffer[i + 1] == '/')365 {366 sc->conv_state.gn[3] = LITERAL2CHAR('.', buffer[i + 2]);367 skip += 2;368 }369 370 /* GZDM4 G0-Designator, 94^n chars */371 else if (buffer[i] == '\033' && buffer[i + 1] == '$'372 && buffer[i + 2] == '(')373 {374 sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 3]);375 skip += 3;376 }377 378 /* G1DM4 G1-Designator, 94^n chars */379 else if (buffer[i] == '\033' && buffer[i + 1] == '$'380 && buffer[i + 2] == ')')381 {382 sc->conv_state.gn[1] = LITERAL2CHAR('$', buffer[i + 3]);383 skip += 3;384 }385 386 /* G2DM4 G2-Designator, 94^n chars */387 else if (buffer[i] == '\033' && buffer[i + 1] == '$'388 && buffer[i + 2] == '*')389 {390 sc->conv_state.gn[2] = LITERAL2CHAR('$', buffer[i + 3]);391 skip += 3;392 }393 394 /* G3DM4 G3-Designator, 94^n chars */395 else if (buffer[i] == '\033' && buffer[i + 1] == '$'396 && buffer[i + 2] == '+')397 {398 sc->conv_state.gn[3] = LITERAL2CHAR('$', buffer[i + 3]);399 skip += 3;400 }401 402 /* G2DM6 G2-Designator, 96^n chars */403 else if (buffer[i] == '\033' && buffer[i + 1] == '$'404 && buffer[i + 2] == '.')405 {406 sc->conv_state.gn[2] = LITERAL3CHAR('$', '.', buffer[i + 3]);407 skip += 3;408 }409 410 /* G3DM6 G3-Designator, 96^n chars */411 else if (buffer[i] == '\033' && buffer[i + 1] == '$'412 && buffer[i + 2] == '/')413 {414 sc->conv_state.gn[3] = LITERAL3CHAR('$', '.', buffer[i + 3]);415 skip += 3;416 }417 else if (buffer[i] == '\033' && buffer[i + 1] == '#')418 {419 debug("ansi private '#' sequence\n");420 421 switch (buffer[i + 2])422 {423 case '8': /* DECALN Fills the entire screen area with424 uppercase Es for screen focus and425 alignment. */426 for (j = 0; j < height; j++)427 {428 for (k = 0; k < width; k++)429 {430 caca_put_char(sc->cv, k, j, 'E');431 }432 }433 x = 0;434 y = 0;435 skip += 2;436 break;437 438 default:439 debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]);440 continue;441 }442 443 }444 /* Interpret escape commands, as per Standard ECMA-48 "Control445 Functions for Coded Character Sets", 5.4. Control sequences. */446 else if (buffer[i] == '\033' && buffer[i + 1] == '[')447 {448 unsigned int argc = 0, argv[101];449 unsigned int param, inter, junk, final;450 451 if (buffer[i + 2] == '?')452 {453 debug("CSI? %c%c%c%c%c\n",454 buffer[i + 3], buffer[i + 4], buffer[i + 5],455 buffer[i + 6], buffer[i + 7]);456 }457 458 /* Compute offsets to parameter bytes, intermediate bytes and to459 the final byte. Only the final byte is mandatory, there can be460 zero of the others. 0 param=2 inter final final+1461 +-----+------------------+---------------------+-----------------+462 | CSI | parameter bytes | intermediate bytes | final byte | | |463 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>?464 | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |465 +-----+------------------+---------------------+-----------------+ */466 param = 2;467 468 /* vttest use to interleave control characters (\014 CR or \010469 BS) into CSI sequences, either directly after ESC[ or after470 param. Can't find anything related to this in any documentation471 nor XTerm sources, thought. */472 473 for (junk = param; i + junk < size; junk++)474 if (buffer[i + junk] < 0x20)475 {476 handle_single_char(buffer[i + junk], &x, &y, screen_list,477 sc);478 }479 else480 {481 break;482 }483 484 /* Intermediate offset */485 for (inter = junk; i + inter < size; inter++)486 if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)487 {488 break;489 }490 /* Interleaved character */491 for (junk = inter; i + junk < size; junk++)492 if (buffer[i + junk] < 0x20)493 {494 handle_single_char(buffer[i + junk], &x, &y, screen_list,495 sc);496 }497 else498 {499 break;500 }501 502 /* Final Byte offset */503 for (final = junk; i + final < size; final++)504 if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)505 {506 break;507 }508 if (i + final >= size509 || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)510 {511 debug("ansi Invalid Final Byte (%d %c)\n", buffer[i + final],512 buffer[i + final]);513 break; /* Invalid Final Byte */514 }515 516 skip += final;517 518 /* Sanity checks */519 if (param < inter && buffer[i + param] >= 0x3c)520 {521 /* Private sequence, only parse what we know */522 debug("ansi import: private sequence \"^[[%.*s\"",523 final - param + 1, buffer + i + param);524 /* FIXME better parsing */525 if (buffer[i + 2] == '?')526 {527 char arg[5];528 int a = 0;529 int c, p;530 for (p = 0; p < 4; p++)531 {532 if (buffer[i + 3 + p] >= '0'533 && buffer[i + 3 + p] <= '9')534 {535 arg[a] = buffer[i + 3 + p];536 arg[a + 1] = 0;537 a++;538 debug("private a now '%s'\n", arg);539 }540 else541 {542 break;543 }544 }545 c = buffer[i + 3 + 4];546 int Pm = atoi(arg);547 debug("private mouse : command %c, arg %d", c, Pm);548 if (c == 'h') /* DECSET DEC Private Mode Set */549 {550 551 switch (Pm)552 {553 /* FIXME Handle different modes */554 case 1000: /* Send Mouse X & Y on button press555 and release. */556 case 1001: /* Use Hilite Mouse Tracking. */557 case 1002: /* Use Cell Motion Mouse Tracking. */558 case 1003: /* Use All Motion Mouse Tracking. */559 sc->report_mouse = 1;560 break;561 default:562 break;563 }564 }565 else if (c == 'l') /* DECRST DEC Private Mode Reset */566 {567 Pm = atoi(arg);568 switch (Pm)569 {570 /* FIXME Handle different modes */571 case 1000: /* Send Mouse X & Y on button press572 and release. */573 case 1001: /* Use Hilite Mouse Tracking. */574 case 1002: /* Use Cell Motion Mouse Tracking. */575 case 1003: /* Use All Motion Mouse Tracking. */576 sc->report_mouse = 0;577 break;578 default:579 break;580 }581 }582 }583 continue; /* Private sequence, skip it entirely */584 }585 586 if (final - param > 100)587 continue; /* Suspiciously long sequence, skip it */588 589 /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string590 format */591 if (param < inter)592 {593 argv[0] = 0;594 for (j = param; j < inter; j++)595 {596 if (buffer[i + j] == ';')597 argv[++argc] = 0;598 else if (buffer[i + j] >= '0' && buffer[i + j] <= '9')599 argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');600 }601 argc++;602 }603 604 /* Interpret final byte. The code representations are given in605 ECMA-48 5.4: Control sequences, and the code definitions are606 given in ECMA-48 8.3: Definition of control functions. */607 debug("ansi import: command '%c'", buffer[i + final]);608 switch (buffer[i + final])609 {610 case 'A': /* CUU (0x41) - Cursor Up */611 y -= argc ? argv[0] : 1;612 if (y < 0)613 y = 0;614 break;615 case 'B': /* CUD (0x42) - Cursor Down */616 y += argc ? argv[0] : 1;617 break;618 case 'C': /* CUF (0x43) - Cursor Right */619 x += argc ? argv[0] : 1;620 break;621 case 'D': /* CUB (0x44) - Cursor Left */622 x -= argc ? argv[0] : 1;623 if (x < 0)624 x = 0;625 break;626 case 'G': /* CHA (0x47) - Cursor Character Absolute */627 x = (argc && argv[0] > 0) ? argv[0] - 1 : 0;628 break;629 case 'H': /* CUP (0x48) - Cursor Position */630 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;631 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;632 debug("ansi CUP : Cursor at %dx%d\n", x, y);633 break;634 case 'J': /* ED (0x4a) - Erase In Page */635 savedattr = caca_get_attr(sc->cv, -1, -1);636 caca_set_attr(sc->cv, sc->clearattr);637 if (!argc || argv[0] == 0)638 {639 caca_draw_line(sc->cv, x, y, width, y, ' ');640 caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' ');641 }642 else if (argv[0] == 1)643 {644 caca_fill_box(sc->cv, 0, 0, width, y, ' ');645 caca_draw_line(sc->cv, 0, y, x, y, ' ');646 }647 else if (argv[0] == 2)648 {649 // x = y = 0;650 caca_fill_box(sc->cv, 0, 0, width, height, ' ');651 }652 caca_set_attr(sc->cv, savedattr);653 break;654 case 'K': /* EL (0x4b) - Erase In Line */655 debug("ansi EL : cursor at %dx%d\n", x, y);656 if (!argc || argv[0] == 0)657 {658 caca_draw_line(sc->cv, x, y, width, y, ' ');659 }660 else if (argv[0] == 1)661 {662 caca_draw_line(sc->cv, 0, y, x, y, ' ');663 }664 else if (argv[0] == 2)665 {666 caca_draw_line(sc->cv, 0, y, width, y, ' ');667 }668 break;669 case 'L': /* IL - Insert line */670 {671 unsigned int nb_lines = argc ? argv[0] : 1;672 for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--)673 {674 for (k = 0; k < width; k++)675 {676 caca_put_char(sc->cv, k, j,677 caca_get_char(sc->cv, k,678 j - nb_lines));679 caca_put_attr(sc->cv, k, j,680 caca_get_attr(sc->cv, k,681 j - nb_lines));682 }683 caca_draw_line(sc->cv, 0, j - nb_lines, width,684 j - nb_lines, ' ');685 }686 }687 break;688 case 'P': /* DCH (0x50) - Delete Character */689 if (!argc || argv[0] == 0)690 argv[0] = 1; /* echo -ne 'foobar\r\e[0P\n' */691 692 for (j = x; (unsigned int)(j + argv[0]) < width; j++)693 {694 caca_put_char(sc->cv, j, y,695 caca_get_char(sc->cv, j + argv[0], y));696 caca_put_attr(sc->cv, j, y,697 caca_get_attr(sc->cv, j + argv[0], y));698 }699 break;700 #if 0701 savedattr = caca_get_attr(sc->cv, -1, -1);702 caca_set_attr(sc->cv, sc->clearattr);703 for (; (unsigned int)j < width; j++)704 caca_put_char(sc->cv, j, y, ' ');705 caca_set_attr(sc->cv, savedattr);706 #endif707 case 'X': /* ECH (0x58) - Erase Character */708 if (argc && argv[0])709 {710 savedattr = caca_get_attr(sc->cv, -1, -1);711 caca_set_attr(sc->cv, sc->clearattr);712 caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' ');713 caca_set_attr(sc->cv, savedattr);714 }715 case 'c': /* DA -- Device Attributes */716 /*717 0 Base VT100, no options 1 Processor options (STP) 2718 Advanced video option (AVO) 3 AVO and STP 4 Graphics719 processor option (GPO) 5 GPO and STP 6 GPO and AVO 7 GPO,720 STP, and AVO */721 /* Warning, argument is Pn */722 debug("ansi Got command c, argc %d, argv[0] (%d)\n", argc,723 argv[0], argv[0]);724 if (!argc || argv[0] == 0)725 {726 send_ansi_sequence(screen_list, "\x1b[?1;0c");727 }728 else729 {730 switch (argv[0])731 {732 case 1:733 send_ansi_sequence(screen_list, "\x1b[?\x1;\x1c");734 break;735 case 2:736 send_ansi_sequence(screen_list, "\x1b[?\x1;\x2c");737 break;738 case 3:739 send_ansi_sequence(screen_list, "\x1b[?\x1;\x3c");740 break;741 case 4:742 send_ansi_sequence(screen_list, "\x1b[?\x1;\x4c");743 break;744 case 5:745 send_ansi_sequence(screen_list, "\x1b[?\x1;\x5c");746 break;747 case 6:748 send_ansi_sequence(screen_list, "\x1b[?\x1;\x6c");749 break;750 case 7:751 send_ansi_sequence(screen_list, "\x1b[?\x1;\x7c");752 break;753 default:754 debug("Unsupported DA option '%d'\n", argv[0]);755 break;756 }757 }758 break;759 case 'd': /* VPA (0x64) - Line Position Absolute */760 y = (argc && argv[0] > 0) ? argv[0] - 1 : 0;761 break;762 case 'f': /* HVP (0x66) - Character And Line Position */763 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;764 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;765 break;766 case 'g': /* TBC -- Tabulation Clear */767 break;768 case 'r': /* FIXME */769 if (argc == 2) /* DCSTBM - Set top and bottom margin */770 {771 debug("DCSTBM %d %d", argv[0], argv[1]);772 top = argv[0];773 bottom = argv[1];774 }775 else776 debug("ansi import: command r with %d params", argc);777 break;778 case 'h': /* SM (0x68) - FIXME */779 debug("ansi import: set mode %i", argc ? (int)argv[0] : -1);780 break;781 case 'l': /* RM (0x6c) - FIXME */782 debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1);783 break;784 case 'm': /* SGR (0x6d) - Select Graphic Rendition */785 if (argc)786 ansi_parse_grcm(sc, argc, argv);787 else788 ansi_parse_grcm(sc, 1, &dummy);789 break;790 case 'n':791 debug("ansi command n, argc %d, argv[0] %d\n", argc, argv[0]);792 if (!argc)793 break;794 795 switch (argv[0])796 {797 case 5:798 /* Term ok */799 send_ansi_sequence(screen_list, "\x1b[0n");800 break;801 case 6:802 /* Cursor Position */803 sprintf(b, "\x1b[%d;%dR", y + 1, x + 1);804 send_ansi_sequence(screen_list, b);805 break;806 }807 808 break;809 case 's': /* Private (save cursor position) */810 save_x = x;811 save_y = y;812 break;813 case 'u': /* Private (reload cursor position) */814 x = save_x;815 y = save_y;816 break;817 default:818 debug("ansi import: unknown command \"^[%.*s\"",819 final - param + 1, buffer + i + param);820 break;821 }822 }823 824 /* Parse OSC stuff. */825 else if (buffer[i] == '\033' && buffer[i + 1] == ']')826 {827 char *string;828 unsigned int command = 0;829 unsigned int mode = 2, semicolon, final;830 831 for (semicolon = mode; i + semicolon < size; semicolon++)832 {833 if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9')834 break;835 command = 10 * command + (buffer[i + semicolon] - '0');836 }837 838 if (i + semicolon >= size || buffer[i + semicolon] != ';')839 break; /* Invalid Mode */840 841 for (final = semicolon + 1; i + final < size; final++)842 if (buffer[i + final] < 0x20)843 break;844 845 if (i + final >= size || buffer[i + final] != '\a')846 break; /* Not enough data or no bell found */847 /* FIXME: XTerm also reacts to <ESC><backslash> and <ST> */848 /* FIXME: differenciate between not enough data (try again) and849 invalid data (print shit) */850 851 skip += final;852 853 string = malloc(final - (semicolon + 1) + 1);854 memcpy(string, buffer + i + (semicolon + 1),855 final - (semicolon + 1));856 string[final - (semicolon + 1)] = '\0';857 debug("ansi import: got OSC command %i string '%s'", command,858 string);859 if (command == 0 || command == 2)860 {861 if (sc->title)862 free(sc->title);863 sc->title = string;864 }865 else866 free(string);867 }868 869 /* Get the character we’re going to paste */870 else871 {872 size_t bytes;873 874 if (i + 6 < size)875 {876 ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes);877 }878 else879 {880 /* Add a trailing zero to what we're going to read */881 char tmp[7];882 memcpy(tmp, buffer + i, size - i);883 tmp[size - i] = '\0';884 ch = caca_utf8_to_utf32(tmp, &bytes);885 }886 887 if (!bytes)888 {889 /* If the Unicode is invalid, assume it was latin1. */890 ch = buffer[i];891 bytes = 1;892 }893 894 /* very incomplete ISO-2022 implementation tailored to DEC ACS */895 if (sc->conv_state.cs == '@')896 {897 if (((ch > ' ') && (ch <= '~'))898 &&899 (sc->900 conv_state.gn[sc->conv_state.ss ? sc->901 conv_state.gn[sc->conv_state.ss] : sc->902 conv_state.glr[0]] == '0'))903 {904 ch = dec_acs(ch);905 }906 else if (((ch > 0x80) && (ch < 0xff))907 && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0'))908 {909 ch = dec_acs(ch + ' ' - 0x80);910 }911 }912 sc->conv_state.ss = 0; /* no single-shift (GL) */913 914 wch = caca_utf32_is_fullwidth(ch) ? 2 : 1;915 916 skip += bytes - 1;917 }918 919 /* Wrap long lines or grow horizontally */920 while ((unsigned int)x + wch > width)921 {922 x -= width;923 y++;924 }925 926 /* Scroll or grow vertically */927 if ((unsigned int)y >= bottom)928 {929 int lines = (y - bottom) + 1;930 931 savedattr = caca_get_attr(sc->cv, -1, -1);932 933 for (j = top - 1; j + lines < bottom; j++)934 {935 for (k = 0; k < width; k++)936 {937 caca_put_char(sc->cv, k, j,938 caca_get_char(sc->cv, k, j + lines));939 caca_put_attr(sc->cv, k, j,940 caca_get_attr(sc->cv, k, j + lines));941 }942 }943 caca_set_attr(sc->cv, sc->clearattr);944 caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' ');945 y -= lines;946 caca_set_attr(sc->cv, savedattr);947 }948 949 /* Now paste our character, if any */950 if (wch)951 {952 caca_put_char(sc->cv, x, y, ch);953 x += wch;954 }955 }956 957 caca_gotoxy(sc->cv, x, y);958 959 if (i)960 sc->changed = 1;961 return i;962 }963 964 /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 (ISO IR965 189) */966 967 static void reset_conv_state(struct screen *sc)968 {969 sc->conv_state.cs = '@'; /* ISO-2022 coding system */970 sc->conv_state.cn[0] = '@'; /* ISO 646 C0 control charset */971 sc->conv_state.cn[1] = 'C'; /* ISO 6429-1983 C1 control charset */972 sc->conv_state.glr[0] = 0; /* G0 in GL */973 sc->conv_state.glr[1] = 2; /* G2 in GR */974 sc->conv_state.gn[0] = 'B'; /* US-ASCII G0 charset */975 sc->conv_state.gn[1] = '0'; /* DEC ACS G1 charset */976 sc->conv_state.gn[2] = LITERAL2CHAR('.', 'A'); /* ISO 8859-1 G2977 charset */978 sc->conv_state.gn[3] = LITERAL2CHAR('.', 'A'); /* ISO 8859-1 G3979 charset */980 sc->conv_state.ss = 0; /* no single-shift (GL) */981 sc->conv_state.ctrl8bit = 1;982 }983 984 /* XXX : ANSI loader helper */985 986 static void ansi_parse_grcm(struct screen *sc,987 unsigned int argc, unsigned int const *argv)988 {989 static uint8_t const ansi2caca[] = {990 CACA_BLACK, CACA_RED, CACA_GREEN, CACA_BROWN,991 CACA_BLUE, CACA_MAGENTA, CACA_CYAN, CACA_LIGHTGRAY992 };993 994 unsigned int j;995 uint8_t efg, ebg; /* Effective (libcaca) fg/bg */996 997 for (j = 0; j < argc; j++)998 {999 /* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */1000 if (argv[j] >= 30 && argv[j] <= 37)1001 sc->fg = ansi2caca[argv[j] - 30];1002 else if (argv[j] >= 40 && argv[j] <= 47)1003 sc->bg = ansi2caca[argv[j] - 40];1004 else if (argv[j] >= 90 && argv[j] <= 97)1005 sc->fg = ansi2caca[argv[j] - 90] + 8;1006 else if (argv[j] >= 100 && argv[j] <= 107)1007 sc->bg = ansi2caca[argv[j] - 100] + 8;1008 else1009 switch (argv[j])1010 {1011 case 0: /* default rendition */1012 sc->fg = sc->dfg;1013 sc->bg = sc->dbg;1014 sc->bold = sc->blink = sc->italics = sc->negative1015 = sc->concealed = sc->underline = sc->faint = sc->strike1016 = sc->proportional = 0;1017 break;1018 case 1: /* bold or increased intensity */1019 sc->bold = 1;1020 break;1021 case 2: /* faint, decreased intensity or second colour1022 */1023 sc->faint = 1;1024 break;1025 case 3: /* italicized */1026 sc->italics = 1;1027 break;1028 case 4: /* singly underlined */1029 sc->underline = 1;1030 break;1031 case 5: /* slowly blinking (less then 150 per minute) */1032 case 6: /* rapidly blinking (150 per minute or more) */1033 sc->blink = 1;1034 break;1035 case 7: /* negative image */1036 sc->negative = 1;1037 break;1038 case 8: /* concealed characters */1039 sc->concealed = 1;1040 break;1041 case 9: /* crossed-out (characters still legible but1042 marked as to be deleted */1043 sc->strike = 1;1044 break;1045 case 21: /* doubly underlined */1046 sc->underline = 1;1047 break;1048 case 22: /* normal colour or normal intensity (neither1049 bold nor faint) */1050 sc->bold = sc->faint = 0;1051 break;1052 case 23: /* not italicized, not fraktur */1053 sc->italics = 0;1054 break;1055 case 24: /* not underlined (neither singly nor doubly) */1056 sc->underline = 0;1057 break;1058 case 25: /* steady (not blinking) */1059 sc->blink = 0;1060 break;1061 case 26: /* (reserved for proportional spacing as1062 specified in CCITT Recommendation T.61) */1063 sc->proportional = 1;1064 break;1065 case 27: /* positive image */1066 sc->negative = 0;1067 break;1068 case 28: /* revealed characters */1069 sc->concealed = 0;1070 break;1071 case 29: /* not crossed out */1072 sc->strike = 0;1073 break;1074 case 38: /* (reserved for future standardization,1075 intended for setting character foreground1076 colour as specified in ISO 8613-6 [CCITT1077 Recommendation T.416]) */1078 break;1079 case 39: /* default display colour1080 (implementation-defined) */1081 sc->fg = sc->dfg;1082 break;1083 case 48: /* (reserved for future standardization,1084 intended for setting character background1085 colour as specified in ISO 8613-6 [CCITT1086 Recommendation T.416]) */1087 break;1088 case 49: /* default background colour1089 (implementation-defined) */1090 sc->bg = sc->dbg;1091 break;1092 case 50: /* (reserved for cancelling the effect of the1093 rendering aspect established by parameter1094 value 26) */1095 sc->proportional = 0;1096 break;1097 default:1098 debug("ansi import: unknown sgr %i", argv[j]);1099 break;1100 }1101 }1102 1103 if (sc->concealed)1104 {1105 efg = ebg = CACA_TRANSPARENT;1106 }1107 else1108 {1109 efg = sc->negative ? sc->bg : sc->fg;1110 ebg = sc->negative ? sc->fg : sc->bg;1111 1112 if (sc->bold)1113 {1114 if (efg < 8)1115 efg += 8;1116 else if (efg == CACA_DEFAULT)1117 efg = CACA_WHITE;1118 }1119 }1120 1121 caca_set_color_ansi(sc->cv, efg, ebg);1122 }1123 33 1124 34 int create_pty(char *cmd, unsigned int w, unsigned int h, int *cpid)
Note: See TracChangeset
for help on using the changeset viewer.