Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

1231 строка
38 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright © 2002—2021 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * This library is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What the Fuck You Want
  9. * to Public License, Version 2, as published by Sam Hocevar. See
  10. * http://www.wtfpl.net/ for more details.
  11. */
  12. /*
  13. * This file contains horizontal and vertical flipping routines.
  14. */
  15. #include "config.h"
  16. #if !defined(__KERNEL__)
  17. # include <stdlib.h>
  18. #endif
  19. #include "caca.h"
  20. #include "caca_internals.h"
  21. static uint32_t flipchar(uint32_t ch);
  22. static uint32_t flopchar(uint32_t ch);
  23. static uint32_t rotatechar(uint32_t ch);
  24. static uint32_t leftchar(uint32_t ch);
  25. static uint32_t rightchar(uint32_t ch);
  26. static void leftpair(uint32_t pair[2]);
  27. static void rightpair(uint32_t pair[2]);
  28. /** \brief Invert a canvas' colours.
  29. *
  30. * Invert a canvas' colours (black becomes white, red becomes cyan, etc.)
  31. * without changing the characters in it.
  32. *
  33. * This function never fails.
  34. *
  35. * \param cv The canvas to invert.
  36. * \return This function always returns 0.
  37. */
  38. int caca_invert(caca_canvas_t *cv)
  39. {
  40. uint32_t *attrs = cv->attrs;
  41. int i;
  42. for(i = cv->height * cv->width; i--; )
  43. {
  44. *attrs = *attrs ^ 0x000f000f;
  45. attrs++;
  46. }
  47. if(!cv->dirty_disabled)
  48. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  49. return 0;
  50. }
  51. /** \brief Flip a canvas horizontally.
  52. *
  53. * Flip a canvas horizontally, choosing characters that look like the
  54. * mirrored version wherever possible. Some characters will stay
  55. * unchanged by the process, but the operation is guaranteed to be
  56. * involutive: performing it again gives back the original canvas.
  57. *
  58. * This function never fails.
  59. *
  60. * \param cv The canvas to flip.
  61. * \return This function always returns 0.
  62. */
  63. int caca_flip(caca_canvas_t *cv)
  64. {
  65. int y;
  66. for(y = 0; y < cv->height; y++)
  67. {
  68. uint32_t *cleft = cv->chars + y * cv->width;
  69. uint32_t *cright = cleft + cv->width - 1;
  70. uint32_t *aleft = cv->attrs + y * cv->width;
  71. uint32_t *aright = aleft + cv->width - 1;
  72. while(cleft < cright)
  73. {
  74. uint32_t ch;
  75. uint32_t attr;
  76. /* Swap attributes */
  77. attr = *aright;
  78. *aright-- = *aleft;
  79. *aleft++ = attr;
  80. /* Swap characters */
  81. ch = *cright;
  82. *cright-- = flipchar(*cleft);
  83. *cleft++ = flipchar(ch);
  84. }
  85. if(cleft == cright)
  86. *cleft = flipchar(*cleft);
  87. /* Fix fullwidth characters. Could it be done in one loop? */
  88. cleft = cv->chars + y * cv->width;
  89. cright = cleft + cv->width - 1;
  90. for( ; cleft < cright; cleft++)
  91. {
  92. if(cleft[0] == CACA_MAGIC_FULLWIDTH)
  93. {
  94. cleft[0] = cleft[1];
  95. cleft[1] = CACA_MAGIC_FULLWIDTH;
  96. cleft++;
  97. }
  98. }
  99. }
  100. if(!cv->dirty_disabled)
  101. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  102. return 0;
  103. }
  104. /** \brief Flip a canvas vertically.
  105. *
  106. * Flip a canvas vertically, choosing characters that look like the
  107. * mirrored version wherever possible. Some characters will stay
  108. * unchanged by the process, but the operation is guaranteed to be
  109. * involutive: performing it again gives back the original canvas.
  110. *
  111. * This function never fails.
  112. *
  113. * \param cv The canvas to flop.
  114. * \return This function always returns 0.
  115. */
  116. int caca_flop(caca_canvas_t *cv)
  117. {
  118. int x;
  119. for(x = 0; x < cv->width; x++)
  120. {
  121. uint32_t *ctop = cv->chars + x;
  122. uint32_t *cbottom = ctop + cv->width * (cv->height - 1);
  123. uint32_t *atop = cv->attrs + x;
  124. uint32_t *abottom = atop + cv->width * (cv->height - 1);
  125. while(ctop < cbottom)
  126. {
  127. uint32_t ch;
  128. uint32_t attr;
  129. /* Swap attributes */
  130. attr = *abottom; *abottom = *atop; *atop = attr;
  131. /* Swap characters */
  132. ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
  133. ctop += cv->width; cbottom -= cv->width;
  134. atop += cv->width; abottom -= cv->width;
  135. }
  136. if(ctop == cbottom)
  137. *ctop = flopchar(*ctop);
  138. }
  139. if(!cv->dirty_disabled)
  140. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  141. return 0;
  142. }
  143. /** \brief Rotate a canvas.
  144. *
  145. * Apply a 180-degree transformation to a canvas, choosing characters
  146. * that look like the upside-down version wherever possible. Some
  147. * characters will stay unchanged by the process, but the operation is
  148. * guaranteed to be involutive: performing it again gives back the
  149. * original canvas.
  150. *
  151. * This function never fails.
  152. *
  153. * \param cv The canvas to rotate.
  154. * \return This function always returns 0.
  155. */
  156. int caca_rotate_180(caca_canvas_t *cv)
  157. {
  158. uint32_t *cbegin = cv->chars;
  159. uint32_t *cend = cbegin + cv->width * cv->height - 1;
  160. uint32_t *abegin = cv->attrs;
  161. uint32_t *aend = abegin + cv->width * cv->height - 1;
  162. int y;
  163. if(!cbegin)
  164. return 0;
  165. while(cbegin < cend)
  166. {
  167. uint32_t ch;
  168. uint32_t attr;
  169. /* Swap attributes */
  170. attr = *aend; *aend = *abegin; *abegin = attr;
  171. /* Swap characters */
  172. ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
  173. cbegin++; cend--; abegin++; aend--;
  174. }
  175. if(cbegin == cend)
  176. *cbegin = rotatechar(*cbegin);
  177. /* Fix fullwidth characters. Could it be done in one loop? */
  178. for(y = 0; y < cv->height; y++)
  179. {
  180. cbegin = cv->chars + y * cv->width;
  181. cend = cbegin + cv->width - 1;
  182. for( ; cbegin < cend; cbegin++)
  183. {
  184. if(cbegin[0] == CACA_MAGIC_FULLWIDTH)
  185. {
  186. cbegin[0] = cbegin[1];
  187. cbegin[1] = CACA_MAGIC_FULLWIDTH;
  188. cbegin++;
  189. }
  190. }
  191. }
  192. if(!cv->dirty_disabled)
  193. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  194. return 0;
  195. }
  196. /** \brief Rotate a canvas, 90 degrees counterclockwise.
  197. *
  198. * Apply a 90-degree transformation to a canvas, choosing characters
  199. * that look like the rotated version wherever possible. Characters cells
  200. * are rotated two-by-two. Some characters will stay unchanged by the
  201. * process, some others will be replaced by close equivalents. Fullwidth
  202. * characters at odd horizontal coordinates will be lost. The operation is
  203. * not guaranteed to be reversible at all.
  204. *
  205. * Note that the width of the canvas is divided by two and becomes the
  206. * new height. Height is multiplied by two and becomes the new width. If
  207. * the original width is an odd number, the division is rounded up.
  208. *
  209. * If an error occurs, -1 is returned and \b errno is set accordingly:
  210. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  211. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  212. * happens, the previous canvas handle is still valid.
  213. *
  214. * \param cv The canvas to rotate left.
  215. * \return 0 in case of success, -1 if an error occurred.
  216. */
  217. int caca_rotate_left(caca_canvas_t *cv)
  218. {
  219. uint32_t *newchars, *newattrs;
  220. int x, y, w2, h2;
  221. if(cv->refcount)
  222. {
  223. seterrno(EBUSY);
  224. return -1;
  225. }
  226. /* Save the current frame shortcuts */
  227. _caca_save_frame_info(cv);
  228. w2 = (cv->width + 1) / 2;
  229. h2 = cv->height;
  230. newchars = _caca_alloc2d(w2, h2, 2 * sizeof(uint32_t));
  231. if(!newchars)
  232. {
  233. seterrno(ENOMEM);
  234. return -1;
  235. }
  236. newattrs = _caca_alloc2d(w2, h2, 2 * sizeof(uint32_t));
  237. if(!newattrs)
  238. {
  239. free(newchars);
  240. seterrno(ENOMEM);
  241. return -1;
  242. }
  243. for(y = 0; y < h2; y++)
  244. {
  245. for(x = 0; x < w2; x++)
  246. {
  247. uint32_t pair[2], attr1, attr2;
  248. pair[0] = cv->chars[cv->width * y + x * 2];
  249. attr1 = cv->attrs[cv->width * y + x * 2];
  250. if((cv->width & 1) && x == w2 - 1)
  251. {
  252. /* Special case: odd column */
  253. pair[1] = ' ';
  254. attr2 = attr1;
  255. }
  256. else
  257. {
  258. pair[1] = cv->chars[cv->width * y + x * 2 + 1];
  259. attr2 = cv->attrs[cv->width * y + x * 2 + 1];
  260. }
  261. /* If one of the characters is a space, we simply ignore
  262. * its colour attributes. Otherwise the resulting characters
  263. * may have totally wrong colours. */
  264. if(pair[0] == ' ')
  265. attr1 = attr2;
  266. else if(pair[1] == ' ')
  267. attr2 = attr1;
  268. leftpair(pair);
  269. newchars[(h2 * (w2 - 1 - x) + y) * 2] = pair[0];
  270. newattrs[(h2 * (w2 - 1 - x) + y) * 2] = attr1;
  271. newchars[(h2 * (w2 - 1 - x) + y) * 2 + 1] = pair[1];
  272. newattrs[(h2 * (w2 - 1 - x) + y) * 2 + 1] = attr2;
  273. }
  274. }
  275. free(cv->chars);
  276. free(cv->attrs);
  277. /* Swap X and Y information */
  278. x = cv->frames[cv->frame].x;
  279. y = cv->frames[cv->frame].y;
  280. cv->frames[cv->frame].x = y * 2;
  281. cv->frames[cv->frame].y = (cv->width - 1 - x) / 2;
  282. x = cv->frames[cv->frame].handlex;
  283. y = cv->frames[cv->frame].handley;
  284. cv->frames[cv->frame].handlex = y * 2;
  285. cv->frames[cv->frame].handley = (cv->width - 1 - x) / 2;
  286. cv->frames[cv->frame].width = cv->height * 2;
  287. cv->frames[cv->frame].height = (cv->width + 1) / 2;
  288. cv->frames[cv->frame].chars = newchars;
  289. cv->frames[cv->frame].attrs = newattrs;
  290. /* Reset the current frame shortcuts */
  291. _caca_load_frame_info(cv);
  292. if(!cv->dirty_disabled)
  293. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  294. return 0;
  295. }
  296. /** \brief Rotate a canvas, 90 degrees counterclockwise.
  297. *
  298. * Apply a 90-degree transformation to a canvas, choosing characters
  299. * that look like the rotated version wherever possible. Characters cells
  300. * are rotated two-by-two. Some characters will stay unchanged by the
  301. * process, some others will be replaced by close equivalents. Fullwidth
  302. * characters at odd horizontal coordinates will be lost. The operation is
  303. * not guaranteed to be reversible at all.
  304. *
  305. * Note that the width of the canvas is divided by two and becomes the
  306. * new height. Height is multiplied by two and becomes the new width. If
  307. * the original width is an odd number, the division is rounded up.
  308. *
  309. * If an error occurs, -1 is returned and \b errno is set accordingly:
  310. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  311. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  312. * happens, the previous canvas handle is still valid.
  313. *
  314. * \param cv The canvas to rotate right.
  315. * \return 0 in case of success, -1 if an error occurred.
  316. */
  317. int caca_rotate_right(caca_canvas_t *cv)
  318. {
  319. uint32_t *newchars, *newattrs;
  320. int x, y, w2, h2;
  321. if(cv->refcount)
  322. {
  323. seterrno(EBUSY);
  324. return -1;
  325. }
  326. /* Save the current frame shortcuts */
  327. _caca_save_frame_info(cv);
  328. w2 = (cv->width + 1) / 2;
  329. h2 = cv->height;
  330. newchars = _caca_alloc2d(w2 * 2, h2, sizeof(uint32_t));
  331. if(!newchars)
  332. {
  333. seterrno(ENOMEM);
  334. return -1;
  335. }
  336. newattrs = _caca_alloc2d(w2 * 2, h2, sizeof(uint32_t));
  337. if(!newattrs)
  338. {
  339. free(newchars);
  340. seterrno(ENOMEM);
  341. return -1;
  342. }
  343. for(y = 0; y < h2; y++)
  344. {
  345. for(x = 0; x < w2; x++)
  346. {
  347. uint32_t pair[2], attr1, attr2;
  348. pair[0] = cv->chars[cv->width * y + x * 2];
  349. attr1 = cv->attrs[cv->width * y + x * 2];
  350. if((cv->width & 1) && x == w2 - 1)
  351. {
  352. /* Special case: odd column */
  353. pair[1] = ' ';
  354. attr2 = attr1;
  355. }
  356. else
  357. {
  358. pair[1] = cv->chars[cv->width * y + x * 2 + 1];
  359. attr2 = cv->attrs[cv->width * y + x * 2 + 1];
  360. }
  361. /* If one of the characters is a space, we simply ignore
  362. * its colour attributes. Otherwise the resulting characters
  363. * may have totally wrong colours. */
  364. if(pair[0] == ' ')
  365. attr1 = attr2;
  366. else if(pair[1] == ' ')
  367. attr2 = attr1;
  368. rightpair(pair);
  369. newchars[(h2 * x + h2 - 1 - y) * 2] = pair[0];
  370. newattrs[(h2 * x + h2 - 1 - y) * 2] = attr1;
  371. newchars[(h2 * x + h2 - 1 - y) * 2 + 1] = pair[1];
  372. newattrs[(h2 * x + h2 - 1 - y) * 2 + 1] = attr2;
  373. }
  374. }
  375. free(cv->chars);
  376. free(cv->attrs);
  377. /* Swap X and Y information */
  378. x = cv->frames[cv->frame].x;
  379. y = cv->frames[cv->frame].y;
  380. cv->frames[cv->frame].x = (cv->height - 1 - y) * 2;
  381. cv->frames[cv->frame].y = x / 2;
  382. x = cv->frames[cv->frame].handlex;
  383. y = cv->frames[cv->frame].handley;
  384. cv->frames[cv->frame].handlex = (cv->height - 1 - y) * 2;
  385. cv->frames[cv->frame].handley = x / 2;
  386. cv->frames[cv->frame].width = cv->height * 2;
  387. cv->frames[cv->frame].height = (cv->width + 1) / 2;
  388. cv->frames[cv->frame].chars = newchars;
  389. cv->frames[cv->frame].attrs = newattrs;
  390. /* Reset the current frame shortcuts */
  391. _caca_load_frame_info(cv);
  392. if(!cv->dirty_disabled)
  393. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  394. return 0;
  395. }
  396. /** \brief Rotate and stretch a canvas, 90 degrees counterclockwise.
  397. *
  398. * Apply a 90-degree transformation to a canvas, choosing characters
  399. * that look like the rotated version wherever possible. Some characters
  400. * will stay unchanged by the process, some others will be replaced by
  401. * close equivalents. Fullwidth characters will be lost. The operation is
  402. * not guaranteed to be reversible at all.
  403. *
  404. * Note that the width and height of the canvas are swapped, causing its
  405. * aspect ratio to look stretched.
  406. *
  407. * If an error occurs, -1 is returned and \b errno is set accordingly:
  408. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  409. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  410. * happens, the previous canvas handle is still valid.
  411. *
  412. * \param cv The canvas to rotate left.
  413. * \return 0 in case of success, -1 if an error occurred.
  414. */
  415. int caca_stretch_left(caca_canvas_t *cv)
  416. {
  417. uint32_t *newchars, *newattrs;
  418. int x, y;
  419. if(cv->refcount)
  420. {
  421. seterrno(EBUSY);
  422. return -1;
  423. }
  424. /* Save the current frame shortcuts */
  425. _caca_save_frame_info(cv);
  426. newchars = _caca_alloc2d(cv->width, cv->height, sizeof(uint32_t));
  427. if(!newchars)
  428. {
  429. seterrno(ENOMEM);
  430. return -1;
  431. }
  432. newattrs = _caca_alloc2d(cv->width, cv->height, sizeof(uint32_t));
  433. if(!newattrs)
  434. {
  435. free(newchars);
  436. seterrno(ENOMEM);
  437. return -1;
  438. }
  439. for(y = 0; y < cv->height; y++)
  440. {
  441. for(x = 0; x < cv->width; x++)
  442. {
  443. uint32_t ch, attr;
  444. ch = cv->chars[cv->width * y + x];
  445. attr = cv->attrs[cv->width * y + x];
  446. /* FIXME: do something about fullwidth characters */
  447. ch = leftchar(ch);
  448. newchars[cv->height * (cv->width - 1 - x) + y] = ch;
  449. newattrs[cv->height * (cv->width - 1 - x) + y] = attr;
  450. }
  451. }
  452. free(cv->chars);
  453. free(cv->attrs);
  454. /* Swap X and Y information */
  455. x = cv->frames[cv->frame].x;
  456. y = cv->frames[cv->frame].y;
  457. cv->frames[cv->frame].x = y;
  458. cv->frames[cv->frame].y = cv->width - 1 - x;
  459. x = cv->frames[cv->frame].handlex;
  460. y = cv->frames[cv->frame].handley;
  461. cv->frames[cv->frame].handlex = y;
  462. cv->frames[cv->frame].handley = cv->width - 1 - x;
  463. cv->frames[cv->frame].width = cv->height;
  464. cv->frames[cv->frame].height = cv->width;
  465. cv->frames[cv->frame].chars = newchars;
  466. cv->frames[cv->frame].attrs = newattrs;
  467. /* Reset the current frame shortcuts */
  468. _caca_load_frame_info(cv);
  469. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  470. return 0;
  471. }
  472. /** \brief Rotate and stretch a canvas, 90 degrees clockwise.
  473. *
  474. * Apply a 270-degree transformation to a canvas, choosing characters
  475. * that look like the rotated version wherever possible. Some characters
  476. * will stay unchanged by the process, some others will be replaced by
  477. * close equivalents. Fullwidth characters will be lost. The operation is
  478. * not guaranteed to be reversible at all.
  479. *
  480. * Note that the width and height of the canvas are swapped, causing its
  481. * aspect ratio to look stretched.
  482. *
  483. * If an error occurs, -1 is returned and \b errno is set accordingly:
  484. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  485. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  486. * happens, the previous canvas handle is still valid.
  487. *
  488. * \param cv The canvas to rotate right.
  489. * \return 0 in case of success, -1 if an error occurred.
  490. */
  491. int caca_stretch_right(caca_canvas_t *cv)
  492. {
  493. uint32_t *newchars, *newattrs;
  494. int x, y;
  495. if(cv->refcount)
  496. {
  497. seterrno(EBUSY);
  498. return -1;
  499. }
  500. /* Save the current frame shortcuts */
  501. _caca_save_frame_info(cv);
  502. newchars = _caca_alloc2d(cv->width, cv->height, sizeof(uint32_t));
  503. if(!newchars)
  504. {
  505. seterrno(ENOMEM);
  506. return -1;
  507. }
  508. newattrs = _caca_alloc2d(cv->width, cv->height, sizeof(uint32_t));
  509. if(!newattrs)
  510. {
  511. free(newchars);
  512. seterrno(ENOMEM);
  513. return -1;
  514. }
  515. for(y = 0; y < cv->height; y++)
  516. {
  517. for(x = 0; x < cv->width; x++)
  518. {
  519. uint32_t ch, attr;
  520. ch = cv->chars[cv->width * y + x];
  521. attr = cv->attrs[cv->width * y + x];
  522. /* FIXME: do something about fullwidth characters */
  523. ch = rightchar(ch);
  524. newchars[cv->height * x + cv->height - 1 - y] = ch;
  525. newattrs[cv->height * x + cv->height - 1 - y] = attr;
  526. }
  527. }
  528. free(cv->chars);
  529. free(cv->attrs);
  530. /* Swap X and Y information */
  531. x = cv->frames[cv->frame].x;
  532. y = cv->frames[cv->frame].y;
  533. cv->frames[cv->frame].x = cv->height - 1 - y;
  534. cv->frames[cv->frame].y = x;
  535. x = cv->frames[cv->frame].handlex;
  536. y = cv->frames[cv->frame].handley;
  537. cv->frames[cv->frame].handlex = cv->height - 1 - y;
  538. cv->frames[cv->frame].handley = x;
  539. cv->frames[cv->frame].width = cv->height;
  540. cv->frames[cv->frame].height = cv->width;
  541. cv->frames[cv->frame].chars = newchars;
  542. cv->frames[cv->frame].attrs = newattrs;
  543. /* Reset the current frame shortcuts */
  544. _caca_load_frame_info(cv);
  545. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  546. return 0;
  547. }
  548. /* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
  549. * of linear lookup. */
  550. static uint32_t flipchar(uint32_t ch)
  551. {
  552. int i;
  553. static uint32_t const noflip[] =
  554. {
  555. /* ASCII */
  556. ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
  557. 'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
  558. '_', 'i', 'o', 'v', 'w', 'x', '|',
  559. /* CP437 and box drawing */
  560. 0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
  561. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  562. 0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
  563. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  564. 0x2575, 0x2577, 0x2579, 0x257b, /* ╵ ╷ ╹ ╻ */
  565. 0
  566. };
  567. static uint32_t const pairs[] =
  568. {
  569. /* ASCII */
  570. '(', ')',
  571. '/', '\\',
  572. '<', '>',
  573. '[', ']',
  574. 'b', 'd',
  575. 'p', 'q',
  576. '{', '}',
  577. /* ASCII-Unicode */
  578. ';', 0x204f, /* ; ⁏ */
  579. '`', 0x00b4, /* ` ´ */
  580. ',', 0x02ce, /* , ˎ */
  581. '1', 0x07c1, /* 1 ߁ */
  582. 'B', 0x10412,/* B 𐐒 */
  583. 'C', 0x03fd, /* C Ͻ */
  584. 'D', 0x15e1, /* D ᗡ */
  585. 'E', 0x018e, /* E Ǝ */
  586. 'J', 0x1490, /* J ᒐ */
  587. 'L', 0x2143, /* L ⅃ */
  588. 'N', 0x0418, /* N И */
  589. 'P', 0x1040b,/* P 𐐋 */
  590. 'R', 0x042f, /* R Я */
  591. 'S', 0x01a7, /* S Ƨ */
  592. 'c', 0x0254, /* c ɔ */
  593. 'e', 0x0258, /* e ɘ */
  594. /* CP437 */
  595. 0x258c, 0x2590, /* ▌ ▐ */
  596. 0x2596, 0x2597, /* ▖ ▗ */
  597. 0x2598, 0x259d, /* ▘ ▝ */
  598. 0x2599, 0x259f, /* ▙ ▟ */
  599. 0x259a, 0x259e, /* ▚ ▞ */
  600. 0x259b, 0x259c, /* ▛ ▜ */
  601. 0x25ba, 0x25c4, /* ► ◄ */
  602. 0x2192, 0x2190, /* → ← */
  603. 0x2310, 0xac, /* ⌐ ¬ */
  604. /* Box drawing */
  605. 0x250c, 0x2510, /* ┌ ┐ */
  606. 0x2514, 0x2518, /* └ ┘ */
  607. 0x251c, 0x2524, /* ├ ┤ */
  608. 0x250f, 0x2513, /* ┏ ┓ */
  609. 0x2517, 0x251b, /* ┗ ┛ */
  610. 0x2523, 0x252b, /* ┣ ┫ */
  611. 0x2552, 0x2555, /* ╒ ╕ */
  612. 0x2558, 0x255b, /* ╘ ╛ */
  613. 0x2553, 0x2556, /* ╓ ╖ */
  614. 0x2559, 0x255c, /* ╙ ╜ */
  615. 0x2554, 0x2557, /* ╔ ╗ */
  616. 0x255a, 0x255d, /* ╚ ╝ */
  617. 0x255e, 0x2561, /* ╞ ╡ */
  618. 0x255f, 0x2562, /* ╟ ╢ */
  619. 0x2560, 0x2563, /* ╠ ╣ */
  620. 0x2574, 0x2576, /* ╴ ╶ */
  621. 0x2578, 0x257a, /* ╸ ╺ */
  622. /* Misc Unicode */
  623. 0x22f2, 0x22fa, /* ⋲ ⋺ */
  624. 0x22f3, 0x22fb, /* ⋳ ⋻ */
  625. 0x2308, 0x2309, /* ⌈ ⌉ */
  626. 0x230a, 0x230b, /* ⌊ ⌋ */
  627. 0x230c, 0x230d, /* ⌌ ⌍ */
  628. 0x230e, 0x230f, /* ⌎ ⌏ */
  629. 0x231c, 0x231d, /* ⌜ ⌝ */
  630. 0x231e, 0x231f, /* ⌞ ⌟ */
  631. 0x2326, 0x232b, /* ⌦ ⌫ */
  632. 0x2329, 0x232a, /* 〈 〉 */
  633. 0x2341, 0x2342, /* ⍁ ⍂ */
  634. 0x2343, 0x2344, /* ⍃ ⍄ */
  635. 0x2345, 0x2346, /* ⍅ ⍆ */
  636. 0x2347, 0x2348, /* ⍇ ⍈ */
  637. 0x233f, 0x2340, /* ⌿ ⍀ */
  638. 0x239b, 0x239e, /* ⎛ ⎞ */
  639. 0x239c, 0x239f, /* ⎜ ⎟ */
  640. 0x239d, 0x23a0, /* ⎝ ⎠ */
  641. 0x23a1, 0x23a4, /* ⎡ ⎤ */
  642. 0x23a2, 0x23a5, /* ⎢ ⎥ */
  643. 0x23a3, 0x23a6, /* ⎣ ⎦ */
  644. 0x23a7, 0x23ab, /* ⎧ ⎫ */
  645. 0x23a8, 0x23ac, /* ⎨ ⎬ */
  646. 0x23a9, 0x23ad, /* ⎩ ⎭ */
  647. 0x23b0, 0x23b1, /* ⎰ ⎱ */
  648. 0x23be, 0x23cb, /* ⎾ ⏋ */
  649. 0x23bf, 0x23cc, /* ⎿ ⏌ */
  650. 0
  651. };
  652. for(i = 0; noflip[i]; i++)
  653. if(ch == noflip[i])
  654. return ch;
  655. for(i = 0; pairs[i]; i++)
  656. if(ch == pairs[i])
  657. return pairs[i ^ 1];
  658. return ch;
  659. }
  660. static uint32_t flopchar(uint32_t ch)
  661. {
  662. int i;
  663. static uint32_t const noflop[] =
  664. {
  665. /* ASCII */
  666. ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
  667. '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
  668. 'c', 'o', '{', '|', '}',
  669. /* CP437 and box drawing */
  670. 0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
  671. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  672. 0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
  673. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  674. 0x2574, 0x2576, 0x2578, 0x257a, /* ╴ ╶ ╸ ╺ */
  675. /* Misc Unicode */
  676. 0x22f2, 0x22fa, 0x22f3, 0x22fb, 0x2326, 0x232b, /* ⋲ ⋺ ⋳ ⋻ ⌦ ⌫ */
  677. 0x2329, 0x232a, 0x2343, 0x2344, 0x2345, 0x2346, /* 〈 〉 ⍃ ⍄ ⍅ ⍆ */
  678. 0x2347, 0x2348, 0x239c, 0x239f, 0x23a2, 0x23a5, /* ⍇ ⍈ ⎜ ⎟ ⎢ ⎥ */
  679. 0x23a8, 0x23ac, /* ⎨ ⎬ */
  680. 0
  681. };
  682. static uint32_t const pairs[] =
  683. {
  684. /* ASCII */
  685. '/', '\\',
  686. 'M', 'W',
  687. ',', '`',
  688. 'b', 'p',
  689. 'd', 'q',
  690. 'p', 'q',
  691. 'f', 't',
  692. '.', '\'',
  693. /* ASCII-Unicode */
  694. '_', 0x203e, /* _ ‾ */
  695. '!', 0x00a1, /* ! ¡ */
  696. 'A', 0x2200, /* A ∀ */
  697. 'J', 0x1489, /* J ᒉ */
  698. 'L', 0x0413, /* L Г */
  699. 'N', 0x0418, /* N И */
  700. 'P', 0x042c, /* P Ь */
  701. 'R', 0x0281, /* R ʁ */
  702. 'S', 0x01a7, /* S Ƨ */
  703. 'U', 0x0548, /* U Ո */
  704. 'V', 0x039b, /* V Λ */
  705. 'Y', 0x2144, /* Y ⅄ */
  706. 'h', 0x03bc, /* h μ */
  707. 'i', 0x1d09, /* i ᴉ */
  708. 'j', 0x1e37, /* j ḷ */
  709. 'l', 0x0237, /* l ȷ */
  710. 'v', 0x028c, /* v ʌ */
  711. 'w', 0x028d, /* w ʍ */
  712. 'y', 0x03bb, /* y λ */
  713. /* Not perfect, but better than nothing */
  714. '"', 0x201e, /* " „ */
  715. 'm', 0x026f, /* m ɯ */
  716. 'n', 'u',
  717. /* CP437 */
  718. 0x2584, 0x2580, /* ▄ ▀ */
  719. 0x2596, 0x2598, /* ▖ ▘ */
  720. 0x2597, 0x259d, /* ▗ ▝ */
  721. 0x2599, 0x259b, /* ▙ ▛ */
  722. 0x259f, 0x259c, /* ▟ ▜ */
  723. 0x259a, 0x259e, /* ▚ ▞ */
  724. /* Box drawing */
  725. 0x250c, 0x2514, /* ┌ └ */
  726. 0x2510, 0x2518, /* ┐ ┘ */
  727. 0x252c, 0x2534, /* ┬ ┴ */
  728. 0x250f, 0x2517, /* ┏ ┗ */
  729. 0x2513, 0x251b, /* ┓ ┛ */
  730. 0x2533, 0x253b, /* ┳ ┻ */
  731. 0x2554, 0x255a, /* ╔ ╚ */
  732. 0x2557, 0x255d, /* ╗ ╝ */
  733. 0x2566, 0x2569, /* ╦ ╩ */
  734. 0x2552, 0x2558, /* ╒ ╘ */
  735. 0x2555, 0x255b, /* ╕ ╛ */
  736. 0x2564, 0x2567, /* ╤ ╧ */
  737. 0x2553, 0x2559, /* ╓ ╙ */
  738. 0x2556, 0x255c, /* ╖ ╜ */
  739. 0x2565, 0x2568, /* ╥ ╨ */
  740. 0x2575, 0x2577, /* ╵ ╷ */
  741. 0x2579, 0x257b, /* ╹ ╻ */
  742. /* Misc Unicode */
  743. 0x2308, 0x230a, /* ⌈ ⌊ */
  744. 0x2309, 0x230b, /* ⌉ ⌋ */
  745. 0x230c, 0x230e, /* ⌌ ⌎ */
  746. 0x230d, 0x230f, /* ⌍ ⌏ */
  747. 0x231c, 0x231e, /* ⌜ ⌞ */
  748. 0x231d, 0x231f, /* ⌝ ⌟ */
  749. 0x2341, 0x2342, /* ⍁ ⍂ */
  750. 0x233f, 0x2340, /* ⌿ ⍀ */
  751. 0x239b, 0x239d, /* ⎛ ⎝ */
  752. 0x239e, 0x23a0, /* ⎞ ⎠ */
  753. 0x23a1, 0x23a3, /* ⎡ ⎣ */
  754. 0x23a4, 0x23a6, /* ⎤ ⎦ */
  755. 0x23a7, 0x23a9, /* ⎧ ⎩ */
  756. 0x23ab, 0x23ad, /* ⎫ ⎭ */
  757. 0x23b0, 0x23b1, /* ⎰ ⎱ */
  758. 0x23be, 0x23bf, /* ⎾ ⎿ */
  759. 0x23cb, 0x23cc, /* ⏋ ⏌ */
  760. 0
  761. };
  762. for(i = 0; noflop[i]; i++)
  763. if(ch == noflop[i])
  764. return ch;
  765. for(i = 0; pairs[i]; i++)
  766. if(ch == pairs[i])
  767. return pairs[i ^ 1];
  768. return ch;
  769. }
  770. static uint32_t rotatechar(uint32_t ch)
  771. {
  772. int i;
  773. static uint32_t const norotate[] =
  774. {
  775. /* ASCII */
  776. ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
  777. 'O', 'S', 'X', 'Z', '\\', 'o', 's', 'x', 'z', '|',
  778. /* Unicode */
  779. 0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
  780. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  781. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  782. /* Misc Unicode */
  783. 0x233f, 0x2340, 0x23b0, 0x23b1, /* ⌿ ⍀ ⎰ ⎱ */
  784. 0
  785. };
  786. static uint32_t const pairs[] =
  787. {
  788. /* ASCII */
  789. '(', ')',
  790. '<', '>',
  791. '[', ']',
  792. '{', '}',
  793. '.', '\'',
  794. '6', '9',
  795. 'M', 'W',
  796. 'b', 'q',
  797. 'd', 'p',
  798. 'n', 'u',
  799. /* ASCII-Unicode */
  800. '_', 0x203e, /* _ ‾ */
  801. ',', 0x00b4, /* , ´ */
  802. ';', 0x061b, /* ; ؛ */
  803. '`', 0x02ce, /* ` ˎ */
  804. '&', 0x214b, /* & ⅋ */
  805. '!', 0x00a1, /* ! ¡ */
  806. '?', 0x00bf, /* ? ¿ */
  807. '3', 0x0190, /* 3 Ɛ */
  808. '4', 0x152d, /* 4 ᔭ */
  809. 'A', 0x2200, /* A ∀ */
  810. 'B', 0x10412,/* B 𐐒 */
  811. 'C', 0x03fd, /* C Ͻ */
  812. 'D', 0x15e1, /* D ᗡ */
  813. 'E', 0x018e, /* E Ǝ */
  814. 'F', 0x2132, /* F Ⅎ -- 0x07c3 looks better, but is RTL */
  815. 'G', 0x2141, /* G ⅁ */
  816. 'J', 0x148b, /* J ᒋ */
  817. 'L', 0x2142, /* L ⅂ */
  818. 'P', 0x0500, /* P Ԁ */
  819. 'Q', 0x038c, /* Q Ό */
  820. 'R', 0x1d1a, /* R ᴚ */
  821. 'T', 0x22a5, /* T ⊥ */
  822. 'U', 0x0548, /* U Ո */
  823. 'V', 0x039b, /* V Λ */
  824. 'Y', 0x2144, /* Y ⅄ */
  825. 'a', 0x0250, /* a ɐ */
  826. 'c', 0x0254, /* c ɔ */
  827. 'e', 0x01dd, /* e ǝ */
  828. 'f', 0x025f, /* f ɟ */
  829. 'g', 0x1d77, /* g ᵷ */
  830. 'h', 0x0265, /* h ɥ */
  831. 'i', 0x1d09, /* i ᴉ */
  832. 'j', 0x1e37, /* j ḷ */
  833. 'k', 0x029e, /* k ʞ */
  834. 'l', 0x0237, /* l ȷ */
  835. 'm', 0x026f, /* m ɯ */
  836. 'r', 0x0279, /* r ɹ */
  837. 't', 0x0287, /* t ʇ */
  838. 'v', 0x028c, /* v ʌ */
  839. 'w', 0x028d, /* w ʍ */
  840. 'y', 0x028e, /* y ʎ */
  841. /* Unicode-ASCII to match third-party software */
  842. 0x0183, 'g', /* ƃ g */
  843. 0x0259, 'e', /* ə e */
  844. 0x027e, 'j', /* ɾ j */
  845. 0x02d9, '.', /* ˙ . */
  846. 0x05df, 'l', /* ן l */
  847. /* Not perfect, but better than nothing */
  848. '"', 0x201e, /* " „ */
  849. /* Misc Unicode */
  850. 0x00e6, 0x1d02, /* æ ᴂ */
  851. 0x0153, 0x1d14, /* œ ᴔ */
  852. 0x03b5, 0x025c, /* ε ɜ */
  853. 0x025b, 0x025c, /* ɛ ɜ */
  854. /* CP437 */
  855. 0x258c, 0x2590, /* ▌ ▐ */
  856. 0x2584, 0x2580, /* ▄ ▀ */
  857. 0x2596, 0x259d, /* ▖ ▝ */
  858. 0x2597, 0x2598, /* ▗ ▘ */
  859. 0x2599, 0x259c, /* ▙ ▜ */
  860. 0x259f, 0x259b, /* ▟ ▛ */
  861. /* Box drawing */
  862. 0x250c, 0x2518, /* ┌ ┘ */
  863. 0x2510, 0x2514, /* ┐ └ */
  864. 0x251c, 0x2524, /* ├ ┤ */
  865. 0x252c, 0x2534, /* ┬ ┴ */
  866. 0x250f, 0x251b, /* ┏ ┛ */
  867. 0x2513, 0x2517, /* ┓ ┗ */
  868. 0x2523, 0x252b, /* ┣ ┫ */
  869. 0x2533, 0x253b, /* ┳ ┻ */
  870. 0x2554, 0x255d, /* ╔ ╝ */
  871. 0x2557, 0x255a, /* ╗ ╚ */
  872. 0x2560, 0x2563, /* ╠ ╣ */
  873. 0x2566, 0x2569, /* ╦ ╩ */
  874. 0x2552, 0x255b, /* ╒ ╛ */
  875. 0x2555, 0x2558, /* ╕ ╘ */
  876. 0x255e, 0x2561, /* ╞ ╡ */
  877. 0x2564, 0x2567, /* ╤ ╧ */
  878. 0x2553, 0x255c, /* ╓ ╜ */
  879. 0x2556, 0x2559, /* ╖ ╙ */
  880. 0x255f, 0x2562, /* ╟ ╢ */
  881. 0x2565, 0x2568, /* ╥ ╨ */
  882. 0x2574, 0x2576, /* ╴ ╶ */
  883. 0x2575, 0x2577, /* ╵ ╷ */
  884. 0x2578, 0x257a, /* ╸ ╺ */
  885. 0x2579, 0x257b, /* ╹ ╻ */
  886. /* Misc Unicode */
  887. 0x22f2, 0x22fa, /* ⋲ ⋺ */
  888. 0x22f3, 0x22fb, /* ⋳ ⋻ */
  889. 0x2308, 0x230b, /* ⌈ ⌋ */
  890. 0x2309, 0x230a, /* ⌉ ⌊ */
  891. 0x230c, 0x230f, /* ⌌ ⌏ */
  892. 0x230d, 0x230e, /* ⌍ ⌎ */
  893. 0x231c, 0x231f, /* ⌜ ⌟ */
  894. 0x231d, 0x231e, /* ⌝ ⌞ */
  895. 0x2326, 0x232b, /* ⌦ ⌫ */
  896. 0x2329, 0x232a, /* 〈 〉 */
  897. 0x2343, 0x2344, /* ⍃ ⍄ */
  898. 0x2345, 0x2346, /* ⍅ ⍆ */
  899. 0x2347, 0x2348, /* ⍇ ⍈ */
  900. 0x239b, 0x23a0, /* ⎛ ⎠ */
  901. 0x239c, 0x239f, /* ⎜ ⎟ */
  902. 0x239e, 0x239d, /* ⎞ ⎝ */
  903. 0x23a1, 0x23a6, /* ⎡ ⎦ */
  904. 0x23a2, 0x23a5, /* ⎢ ⎥ */
  905. 0x23a4, 0x23a3, /* ⎤ ⎣ */
  906. 0x23a7, 0x23ad, /* ⎧ ⎭ */
  907. 0x23a8, 0x23ac, /* ⎨ ⎬ */
  908. 0x23ab, 0x23a9, /* ⎫ ⎩ */
  909. 0x23be, 0x23cc, /* ⎾ ⏌ */
  910. 0x23cb, 0x23bf, /* ⏋ ⎿ */
  911. 0
  912. };
  913. for(i = 0; norotate[i]; i++)
  914. if(ch == norotate[i])
  915. return ch;
  916. for(i = 0; pairs[i]; i++)
  917. if(ch == pairs[i])
  918. return pairs[i ^ 1];
  919. return ch;
  920. }
  921. static uint32_t const leftright2[] =
  922. {
  923. /* ASCII */
  924. '/', '\\',
  925. '|', '-',
  926. '|', '_', /* This is all right because there was already a '|' before */
  927. /* ASCII-Unicode */
  928. '|', 0x203e, /* | ‾ */
  929. /* Misc Unicode */
  930. 0x2571, 0x2572, /* ╱ ╲ */
  931. /* Box drawing */
  932. 0x2500, 0x2502, /* ─ │ */
  933. 0x2501, 0x2503, /* ━ ┃ */
  934. 0x2550, 0x2551, /* ═ ║ */
  935. 0, 0
  936. };
  937. static uint32_t const leftright4[] =
  938. {
  939. /* ASCII */
  940. '<', 'v', '>', '^',
  941. ',', '.', '\'', '`',
  942. /* ASCII / Unicode */
  943. '(', 0x203f, ')', 0x2040, /* ( ‿ ) ⁀ */
  944. /* Misc Unicode */
  945. 0x256d, 0x2570, 0x256f, 0x256e, /* ╭ ╰ ╯ ╮ */
  946. /* CP437 */
  947. 0x258c, 0x2584, 0x2590, 0x2580, /* ▌ ▄ ▐ ▀ */
  948. 0x2596, 0x2597, 0x259d, 0x2598, /* ▖ ▗ ▝ ▘ */
  949. 0x2599, 0x259f, 0x259c, 0x259b, /* ▙ ▟ ▜ ▛ */
  950. /* Box drawing */
  951. 0x250c, 0x2514, 0x2518, 0x2510, /* ┌ └ ┘ ┐ */
  952. 0x250f, 0x2517, 0x251b, 0x2513, /* ┏ ┗ ┛ ┓ */
  953. 0x251c, 0x2534, 0x2524, 0x252c, /* ├ ┴ ┤ ┬ */
  954. 0x2523, 0x253b, 0x252b, 0x2533, /* ┣ ┻ ┫ ┳ */
  955. 0x2552, 0x2559, 0x255b, 0x2556, /* ╒ ╙ ╛ ╖ */
  956. 0x2553, 0x2558, 0x255c, 0x2555, /* ╓ ╘ ╜ ╕ */
  957. 0x2554, 0x255a, 0x255d, 0x2557, /* ╔ ╚ ╝ ╗ */
  958. 0x255e, 0x2568, 0x2561, 0x2565, /* ╞ ╨ ╡ ╥ */
  959. 0x255f, 0x2567, 0x2562, 0x2564, /* ╟ ╧ ╢ ╤ */
  960. 0x2560, 0x2569, 0x2563, 0x2566, /* ╠ ╩ ╣ ╦ */
  961. 0x2574, 0x2577, 0x2576, 0x2575, /* ╴ ╷ ╶ ╵ */
  962. 0x2578, 0x257b, 0x257a, 0x2579, /* ╸ ╻ ╺ ╹ */
  963. 0, 0, 0, 0
  964. };
  965. static uint32_t leftchar(uint32_t ch)
  966. {
  967. int i;
  968. for(i = 0; leftright2[i]; i++)
  969. if(ch == leftright2[i])
  970. return leftright2[(i & ~1) | ((i + 1) & 1)];
  971. for(i = 0; leftright4[i]; i++)
  972. if(ch == leftright4[i])
  973. return leftright4[(i & ~3) | ((i + 1) & 3)];
  974. return ch;
  975. }
  976. static uint32_t rightchar(uint32_t ch)
  977. {
  978. int i;
  979. for(i = 0; leftright2[i]; i++)
  980. if(ch == leftright2[i])
  981. return leftright2[(i & ~1) | ((i - 1) & 1)];
  982. for(i = 0; leftright4[i]; i++)
  983. if(ch == leftright4[i])
  984. return leftright4[(i & ~3) | ((i - 1) & 3)];
  985. return ch;
  986. }
  987. static uint32_t const leftright2x2[] =
  988. {
  989. /* ASCII / Unicode */
  990. '-', '-', 0x4e28, CACA_MAGIC_FULLWIDTH, /* -- 丨 */
  991. '|', '|', 0x2f06, CACA_MAGIC_FULLWIDTH, /* || ⼆ */
  992. /* Unicode */
  993. 0x2584, 0x2580, 0x2580, 0x2584, /* ▄▀ ▀▄ */
  994. 0, 0, 0, 0
  995. };
  996. static uint32_t const leftright2x4[] =
  997. {
  998. /* ASCII */
  999. ':', ' ', '.', '.', ' ', ':', '\'', '\'',
  1000. /* ASCII / Unicode */
  1001. ' ', '`', 0x00b4, ' ', 0x02ce, ' ', ' ', ',', /* ` ´ ˎ , */
  1002. ' ', '`', '\'', ' ', '.', ' ', ' ', ',', /* fallback ASCII */
  1003. '`', ' ', ',', ' ', ' ', 0x00b4, ' ', 0x02ce, /* ` , ˎ ´ */
  1004. '`', ' ', ',', ' ', ' ', '.', ' ', '\'', /* fallback ASCII */
  1005. '/', ' ', '-', 0x02ce, ' ', '/', '`', '-', /* / -ˎ / `- */
  1006. '/', ' ', '-', '.', ' ', '/', '\'', '-', /* fallback ASCII */
  1007. '\\', ' ', ',', '-', ' ', '\\', '-', 0x00b4, /* \ ,- \ -´ */
  1008. '\\', ' ', '.', '-', ' ', '\\', '-', '\'', /* fallback ASCII */
  1009. '\\', ' ', '_', ',', ' ', '\\', 0x00b4, 0x203e, /* \ _, \ ´‾ */
  1010. '\\', '_', '_', '/', 0x203e, '\\', '/', 0x203e, /* \_ _/ ‾\ /‾ */
  1011. '_', '\\', 0x203e, '/', '\\', 0x203e, '/', '_', /* _\ ‾/ \‾ /_ */
  1012. '|', ' ', '_', '_', ' ', '|', 0x203e, 0x203e, /* | __ | ‾‾ */
  1013. '_', '|', 0x203e, '|', '|', 0x203e, '|', '_', /* _| ‾| |‾ |_ */
  1014. '|', '_', '_', '|', 0x203e, '|', '|', 0x203e, /* |_ _| ‾| |‾ */
  1015. '_', ' ', ' ', 0x2577, ' ', 0x203e, 0x2575, ' ', /* _ ╷ ‾ ╵ */
  1016. ' ', '_', ' ', 0x2575, 0x203e, ' ', 0x2577, ' ', /* _ ╵ ‾ ╷ */
  1017. '.', '_', '.', 0x2575, 0x203e, '\'', 0x2577, '\'', /* ._ .╵ ‾' ╷' */
  1018. '(', '_', 0x203f, '|', 0x203e, ')', '|', 0x2040, /* (_ ‿| ‾) |⁀ */
  1019. '(', 0x203e, '|', 0x203f, '_', ')', 0x2040, '|', /* (‾ |‿ _) ⁀| */
  1020. '\\', '/', 0xff1e, CACA_MAGIC_FULLWIDTH,
  1021. '/', '\\', 0xff1c, CACA_MAGIC_FULLWIDTH, /* \/ > /\ < */
  1022. ')', ' ', 0xfe35, CACA_MAGIC_FULLWIDTH,
  1023. ' ', '(', 0xfe36, CACA_MAGIC_FULLWIDTH, /* ) ︵ ( ︶ */
  1024. '}', ' ', 0xfe37, CACA_MAGIC_FULLWIDTH,
  1025. ' ', '{', 0xfe38, CACA_MAGIC_FULLWIDTH, /* } ︷ { ︸ */
  1026. /* Not perfect, but better than nothing */
  1027. '(', ' ', 0x02ce, ',', ' ', ')', 0x00b4, '`', /* ( ˎ, ) ´` */
  1028. ' ', 'v', '>', ' ', 0x028c, ' ', ' ', '<', /* v > ʌ < */
  1029. ' ', 'V', '>', ' ', 0x039b, ' ', ' ', '<', /* V > Λ < */
  1030. 'v', ' ', '>', ' ', ' ', 0x028c, ' ', '<', /* v > ʌ < */
  1031. 'V', ' ', '>', ' ', ' ', 0x039b, ' ', '<', /* V > Λ < */
  1032. '\\', '|', 0xff1e, CACA_MAGIC_FULLWIDTH,
  1033. '|', '\\', 0xff1c, CACA_MAGIC_FULLWIDTH, /* \| > |\ < */
  1034. '|', '/', 0xff1e, CACA_MAGIC_FULLWIDTH,
  1035. '/', '|', 0xff1c, CACA_MAGIC_FULLWIDTH, /* |/ > /| < */
  1036. /* Unicode */
  1037. 0x2584, ' ', ' ', 0x2584, ' ', 0x2580, 0x2580, ' ', /* ▄ ▄ ▀ ▀ */
  1038. 0x2588, ' ', 0x2584, 0x2584, ' ', 0x2588, 0x2580, 0x2580, /* █ ▄▄ █ ▀▀ */
  1039. 0x2588, 0x2584, 0x2584, 0x2588,
  1040. 0x2580, 0x2588, 0x2588, 0x2580, /* █▄ ▄█ ▀█ █▀ */
  1041. /* TODO: Braille */
  1042. /* Not perfect, but better than nothing */
  1043. 0x2591, ' ', 0x28e4, 0x28e4, ' ', 0x2591, 0x281b, 0x281b, /* ░ ⣤⣤ ░ ⠛⠛ */
  1044. 0x2592, ' ', 0x28f6, 0x28f6, ' ', 0x2592, 0x283f, 0x283f, /* ▒ ⣶⣶ ▒ ⠿⠿ */
  1045. 0, 0, 0, 0, 0, 0, 0, 0
  1046. };
  1047. static void leftpair(uint32_t pair[2])
  1048. {
  1049. int i;
  1050. for(i = 0; leftright2x2[i]; i += 2)
  1051. if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
  1052. {
  1053. pair[0] = leftright2x2[(i & ~3) | ((i + 2) & 3)];
  1054. pair[1] = leftright2x2[((i & ~3) | ((i + 2) & 3)) + 1];
  1055. return;
  1056. }
  1057. for(i = 0; leftright2x4[i]; i += 2)
  1058. if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
  1059. {
  1060. pair[0] = leftright2x4[(i & ~7) | ((i + 2) & 7)];
  1061. pair[1] = leftright2x4[((i & ~7) | ((i + 2) & 7)) + 1];
  1062. return;
  1063. }
  1064. }
  1065. static void rightpair(uint32_t pair[2])
  1066. {
  1067. int i;
  1068. for(i = 0; leftright2x2[i]; i += 2)
  1069. if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
  1070. {
  1071. pair[0] = leftright2x2[(i & ~3) | ((i - 2) & 3)];
  1072. pair[1] = leftright2x2[((i & ~3) | ((i - 2) & 3)) + 1];
  1073. return;
  1074. }
  1075. for(i = 0; leftright2x4[i]; i += 2)
  1076. if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
  1077. {
  1078. pair[0] = leftright2x4[(i & ~7) | ((i - 2) & 7)];
  1079. pair[1] = leftright2x4[((i & ~7) | ((i - 2) & 7)) + 1];
  1080. return;
  1081. }
  1082. }