25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1157 lines
40 KiB

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