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

952 lines
28 KiB

  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library 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://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains horizontal and vertical flipping routines.
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #if !defined(__KERNEL__)
  20. # include <stdlib.h>
  21. #endif
  22. #include "cucul.h"
  23. #include "cucul_internals.h"
  24. static uint32_t flipchar(uint32_t ch);
  25. static uint32_t flopchar(uint32_t ch);
  26. static uint32_t rotatechar(uint32_t ch);
  27. static uint32_t leftchar(uint32_t ch);
  28. static uint32_t rightchar(uint32_t ch);
  29. /** \brief Invert a canvas' colours.
  30. *
  31. * Invert a canvas' colours (black becomes white, red becomes cyan, etc.)
  32. * without changing the characters in it.
  33. *
  34. * This function never fails.
  35. *
  36. * \param cv The canvas to invert.
  37. * \return This function always returns 0.
  38. */
  39. int cucul_invert(cucul_canvas_t *cv)
  40. {
  41. uint32_t *attrs = cv->attrs;
  42. unsigned int i;
  43. for(i = cv->height * cv->width; i--; )
  44. {
  45. *attrs = *attrs ^ 0x000f000f;
  46. attrs++;
  47. }
  48. return 0;
  49. }
  50. /** \brief Flip a canvas horizontally.
  51. *
  52. * Flip a canvas horizontally, choosing characters that look like the
  53. * mirrored version wherever possible. Some characters will stay
  54. * unchanged by the process, but the operation is guaranteed to be
  55. * involutive: performing it again gives back the original canvas.
  56. *
  57. * This function never fails.
  58. *
  59. * \param cv The canvas to flip.
  60. * \return This function always returns 0.
  61. */
  62. int cucul_flip(cucul_canvas_t *cv)
  63. {
  64. unsigned int y;
  65. for(y = 0; y < cv->height; y++)
  66. {
  67. uint32_t *cleft = cv->chars + y * cv->width;
  68. uint32_t *cright = cleft + cv->width - 1;
  69. uint32_t *aleft = cv->attrs + y * cv->width;
  70. uint32_t *aright = aleft + cv->width - 1;
  71. while(cleft < cright)
  72. {
  73. uint32_t ch;
  74. uint32_t attr;
  75. /* Swap attributes */
  76. attr = *aright;
  77. *aright-- = *aleft;
  78. *aleft++ = attr;
  79. /* Swap characters */
  80. ch = *cright;
  81. *cright-- = flipchar(*cleft);
  82. *cleft++ = flipchar(ch);
  83. }
  84. if(cleft == cright)
  85. *cleft = flipchar(*cleft);
  86. /* Fix fullwidth characters. Could it be done in one loop? */
  87. cleft = cv->chars + y * cv->width;
  88. cright = cleft + cv->width - 1;
  89. for( ; cleft < cright; cleft++)
  90. {
  91. if(cleft[0] == CUCUL_MAGIC_FULLWIDTH)
  92. {
  93. cleft[0] = cleft[1];
  94. cleft[1] = CUCUL_MAGIC_FULLWIDTH;
  95. cleft++;
  96. }
  97. }
  98. }
  99. return 0;
  100. }
  101. /** \brief Flip a canvas vertically.
  102. *
  103. * Flip a canvas vertically, choosing characters that look like the
  104. * mirrored version wherever possible. Some characters will stay
  105. * unchanged by the process, but the operation is guaranteed to be
  106. * involutive: performing it again gives back the original canvas.
  107. *
  108. * This function never fails.
  109. *
  110. * \param cv The canvas to flop.
  111. * \return This function always returns 0.
  112. */
  113. int cucul_flop(cucul_canvas_t *cv)
  114. {
  115. unsigned int x;
  116. for(x = 0; x < cv->width; x++)
  117. {
  118. uint32_t *ctop = cv->chars + x;
  119. uint32_t *cbottom = ctop + cv->width * (cv->height - 1);
  120. uint32_t *atop = cv->attrs + x;
  121. uint32_t *abottom = atop + cv->width * (cv->height - 1);
  122. while(ctop < cbottom)
  123. {
  124. uint32_t ch;
  125. uint32_t attr;
  126. /* Swap attributes */
  127. attr = *abottom; *abottom = *atop; *atop = attr;
  128. /* Swap characters */
  129. ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
  130. ctop += cv->width; cbottom -= cv->width;
  131. atop += cv->width; abottom -= cv->width;
  132. }
  133. if(ctop == cbottom)
  134. *ctop = flopchar(*ctop);
  135. }
  136. return 0;
  137. }
  138. /** \brief Rotate a canvas.
  139. *
  140. * Apply a 180-degree transformation to a canvas, choosing characters
  141. * that look like the upside-down version wherever possible. Some
  142. * characters will stay unchanged by the process, but the operation is
  143. * guaranteed to be involutive: performing it again gives back the
  144. * original canvas.
  145. *
  146. * This function never fails.
  147. *
  148. * \param cv The canvas to rotate.
  149. * \return This function always returns 0.
  150. */
  151. int cucul_rotate_180(cucul_canvas_t *cv)
  152. {
  153. uint32_t *cbegin = cv->chars;
  154. uint32_t *cend = cbegin + cv->width * cv->height - 1;
  155. uint32_t *abegin = cv->attrs;
  156. uint32_t *aend = abegin + cv->width * cv->height - 1;
  157. unsigned int y;
  158. while(cbegin < cend)
  159. {
  160. uint32_t ch;
  161. uint32_t attr;
  162. /* Swap attributes */
  163. attr = *aend; *aend = *abegin; *abegin = attr;
  164. /* Swap characters */
  165. ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
  166. cbegin++; cend--; abegin++; aend--;
  167. }
  168. if(cbegin == cend)
  169. *cbegin = rotatechar(*cbegin);
  170. /* Fix fullwidth characters. Could it be done in one loop? */
  171. for(y = 0; y < cv->height; y++)
  172. {
  173. cbegin = cv->chars + y * cv->width;
  174. cend = cbegin + cv->width - 1;
  175. for( ; cbegin < cend; cbegin++)
  176. {
  177. if(cbegin[0] == CUCUL_MAGIC_FULLWIDTH)
  178. {
  179. cbegin[0] = cbegin[1];
  180. cbegin[1] = CUCUL_MAGIC_FULLWIDTH;
  181. cbegin++;
  182. }
  183. }
  184. }
  185. return 0;
  186. }
  187. /** \brief Rotate a canvas, 90 degrees counterclockwise.
  188. *
  189. * Apply a 90-degree transformation to a canvas, choosing characters
  190. * that look like the rotated version wherever possible. Some characters
  191. * will stay unchanged by the process, some others will be replaced by
  192. * close equivalents. Fullwidth characters will be lost. The operation is
  193. * not guaranteed to be reversible at all.
  194. *
  195. * Note that the width and height of the canvas are swapped.
  196. *
  197. * If an error occurs, -1 is returned and \b errno is set accordingly:
  198. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  199. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  200. * happens, the previous canvas handle is still valid.
  201. *
  202. * \param cv The canvas to rotate left.
  203. * \return 0 in case of success, -1 if an error occurred.
  204. */
  205. int cucul_rotate_left(cucul_canvas_t *cv)
  206. {
  207. uint32_t *newchars, *newattrs;
  208. unsigned int x, y;
  209. if(cv->refcount)
  210. {
  211. seterrno(EBUSY);
  212. return -1;
  213. }
  214. /* Save the current frame shortcuts */
  215. _cucul_save_frame_info(cv);
  216. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  217. if(!newchars)
  218. return -1;
  219. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  220. if(!newattrs)
  221. {
  222. free(newchars);
  223. return -1;
  224. }
  225. for(y = 0; y < cv->height; y++)
  226. {
  227. for(x = 0; x < cv->width; x++)
  228. {
  229. uint32_t ch, attr;
  230. ch = cv->chars[cv->width * y + x];
  231. attr = cv->attrs[cv->width * y + x];
  232. /* FIXME: do something about fullwidth characters */
  233. ch = leftchar(ch);
  234. newchars[cv->height * (cv->width - 1 - x) + y] = ch;
  235. newattrs[cv->height * (cv->width - 1 - x) + y] = attr;
  236. }
  237. }
  238. free(cv->chars);
  239. free(cv->attrs);
  240. /* Swap X and Y information */
  241. x = cv->frames[cv->frame].x;
  242. y = cv->frames[cv->frame].y;
  243. cv->frames[cv->frame].x = y;
  244. cv->frames[cv->frame].y = cv->width - 1 - x;
  245. x = cv->frames[cv->frame].handlex;
  246. y = cv->frames[cv->frame].handley;
  247. cv->frames[cv->frame].handlex = y;
  248. cv->frames[cv->frame].handley = cv->width - 1 - x;
  249. cv->frames[cv->frame].width = cv->height;
  250. cv->frames[cv->frame].height = cv->width;
  251. cv->frames[cv->frame].chars = newchars;
  252. cv->frames[cv->frame].attrs = newattrs;
  253. /* Reset the current frame shortcuts */
  254. _cucul_load_frame_info(cv);
  255. return 0;
  256. }
  257. /** \brief Rotate a canvas, 90 degrees counterclockwise (widechar version).
  258. *
  259. * Apply a 90-degree transformation to a canvas, choosing characters
  260. * that look like the rotated version wherever possible. Characters cells
  261. * are rotated two-by-two. Some characters will stay unchanged by the
  262. * process, some others will be replaced by close equivalents. Fullwidth
  263. * characters at odd horizontal coordinates will be lost. The operation is
  264. * not guaranteed to be reversible at all.
  265. *
  266. * Note that the width of the canvas is divided by two and becomes the
  267. * new height. Height is multiplied by two and becomes the new width. It
  268. * is illegal to pass a canvas with an odd width to this function.
  269. *
  270. * If an error occurs, -1 is returned and \b errno is set accordingly:
  271. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  272. * - \c EINVAL The canvas' width is odd.
  273. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  274. * happens, the previous canvas handle is still valid.
  275. *
  276. * \param cv The canvas to rotate left.
  277. * \return 0 in case of success, -1 if an error occurred.
  278. */
  279. int cucul_rotate_left_wide(cucul_canvas_t *cv)
  280. {
  281. uint32_t *newchars, *newattrs;
  282. unsigned int x, y, subwidth, subheight;
  283. if(cv->refcount)
  284. {
  285. seterrno(EBUSY);
  286. return -1;
  287. }
  288. if(cv->width & 1)
  289. {
  290. seterrno(EINVAL);
  291. return -1;
  292. }
  293. /* Save the current frame shortcuts */
  294. _cucul_save_frame_info(cv);
  295. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  296. if(!newchars)
  297. return -1;
  298. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  299. if(!newattrs)
  300. {
  301. free(newchars);
  302. return -1;
  303. }
  304. subwidth = cv->width / 2;
  305. subheight = cv->height;
  306. for(y = 0; y < subheight; y++)
  307. {
  308. for(x = 0; x < subwidth; x++)
  309. {
  310. uint32_t ch1, ch2, attr1, attr2;
  311. ch1 = cv->chars[(subwidth * y + x) * 2];
  312. attr1 = cv->attrs[(subwidth * y + x) * 2];
  313. ch2 = cv->chars[(subwidth * y + x) * 2 + 1];
  314. attr2 = cv->attrs[(subwidth * y + x) * 2 + 1];
  315. newchars[(subheight * (subwidth - 1 - x) + y) * 2] = ch1;
  316. newattrs[(subheight * (subwidth - 1 - x) + y) * 2] = attr1;
  317. newchars[(subheight * (subwidth - 1 - x) + y) * 2 + 1] = ch2;
  318. newattrs[(subheight * (subwidth - 1 - x) + y) * 2 + 1] = attr2;
  319. }
  320. }
  321. free(cv->chars);
  322. free(cv->attrs);
  323. /* Swap X and Y information */
  324. x = cv->frames[cv->frame].x;
  325. y = cv->frames[cv->frame].y;
  326. cv->frames[cv->frame].x = y * 2;
  327. cv->frames[cv->frame].y = (cv->width - 1 - x) / 2;
  328. x = cv->frames[cv->frame].handlex;
  329. y = cv->frames[cv->frame].handley;
  330. cv->frames[cv->frame].handlex = y * 2;
  331. cv->frames[cv->frame].handley = (cv->width - 1 - x) / 2;
  332. cv->frames[cv->frame].width = cv->height * 2;
  333. cv->frames[cv->frame].height = cv->width / 2;
  334. cv->frames[cv->frame].chars = newchars;
  335. cv->frames[cv->frame].attrs = newattrs;
  336. /* Reset the current frame shortcuts */
  337. _cucul_load_frame_info(cv);
  338. return 0;
  339. }
  340. /** \brief Rotate a canvas, 90 degrees clockwise.
  341. *
  342. * Apply a 270-degree transformation to a canvas, choosing characters
  343. * that look like the rotated version wherever possible. Some characters
  344. * will stay unchanged by the process, some others will be replaced by
  345. * close equivalents. Fullwidth characters will be lost. The operation is
  346. * not guaranteed to be reversible at all.
  347. *
  348. * Note that the width and height of the canvas are swapped.
  349. *
  350. * If an error occurs, -1 is returned and \b errno is set accordingly:
  351. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  352. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  353. * happens, the previous canvas handle is still valid.
  354. *
  355. * \param cv The canvas to rotate right.
  356. * \return 0 in case of success, -1 if an error occurred.
  357. */
  358. int cucul_rotate_right(cucul_canvas_t *cv)
  359. {
  360. uint32_t *newchars, *newattrs;
  361. unsigned int x, y;
  362. if(cv->refcount)
  363. {
  364. seterrno(EBUSY);
  365. return -1;
  366. }
  367. /* Save the current frame shortcuts */
  368. _cucul_save_frame_info(cv);
  369. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  370. if(!newchars)
  371. {
  372. seterrno(ENOMEM);
  373. return -1;
  374. }
  375. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  376. if(!newattrs)
  377. {
  378. free(newchars);
  379. seterrno(ENOMEM);
  380. return -1;
  381. }
  382. for(y = 0; y < cv->height; y++)
  383. {
  384. for(x = 0; x < cv->width; x++)
  385. {
  386. uint32_t ch, attr;
  387. ch = cv->chars[cv->width * y + x];
  388. attr = cv->attrs[cv->width * y + x];
  389. /* FIXME: do something about fullwidth characters */
  390. ch = rightchar(ch);
  391. newchars[cv->height * x + cv->height - 1 - y] = ch;
  392. newattrs[cv->height * x + cv->height - 1 - y] = attr;
  393. }
  394. }
  395. free(cv->chars);
  396. free(cv->attrs);
  397. /* Swap X and Y information */
  398. x = cv->frames[cv->frame].x;
  399. y = cv->frames[cv->frame].y;
  400. cv->frames[cv->frame].x = cv->height - 1 - y;
  401. cv->frames[cv->frame].y = x;
  402. x = cv->frames[cv->frame].handlex;
  403. y = cv->frames[cv->frame].handley;
  404. cv->frames[cv->frame].handlex = cv->height - 1 - y;
  405. cv->frames[cv->frame].handley = x;
  406. cv->frames[cv->frame].width = cv->height;
  407. cv->frames[cv->frame].height = cv->width;
  408. cv->frames[cv->frame].chars = newchars;
  409. cv->frames[cv->frame].attrs = newattrs;
  410. /* Reset the current frame shortcuts */
  411. _cucul_load_frame_info(cv);
  412. return 0;
  413. }
  414. /** \brief Rotate a canvas, 90 degrees counterclockwise (widechar version).
  415. *
  416. * Apply a 90-degree transformation to a canvas, choosing characters
  417. * that look like the rotated version wherever possible. Characters cells
  418. * are rotated two-by-two. Some characters will stay unchanged by the
  419. * process, some others will be replaced by close equivalents. Fullwidth
  420. * characters at odd horizontal coordinates will be lost. The operation is
  421. * not guaranteed to be reversible at all.
  422. *
  423. * Note that the width of the canvas is divided by two and becomes the
  424. * new height. Height is multiplied by two and becomes the new width. It
  425. * is illegal to pass a canvas with an odd width to this function.
  426. *
  427. * If an error occurs, -1 is returned and \b errno is set accordingly:
  428. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  429. * - \c EINVAL The canvas' width is odd.
  430. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  431. * happens, the previous canvas handle is still valid.
  432. *
  433. * \param cv The canvas to rotate right.
  434. * \return 0 in case of success, -1 if an error occurred.
  435. */
  436. int cucul_rotate_right_wide(cucul_canvas_t *cv)
  437. {
  438. uint32_t *newchars, *newattrs;
  439. unsigned int x, y, subwidth, subheight;
  440. if(cv->refcount)
  441. {
  442. seterrno(EBUSY);
  443. return -1;
  444. }
  445. if(cv->width & 1)
  446. {
  447. seterrno(EINVAL);
  448. return -1;
  449. }
  450. /* Save the current frame shortcuts */
  451. _cucul_save_frame_info(cv);
  452. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  453. if(!newchars)
  454. return -1;
  455. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  456. if(!newattrs)
  457. {
  458. free(newchars);
  459. return -1;
  460. }
  461. subwidth = cv->width / 2;
  462. subheight = cv->height;
  463. for(y = 0; y < subheight; y++)
  464. {
  465. for(x = 0; x < subwidth; x++)
  466. {
  467. uint32_t ch1, ch2, attr1, attr2;
  468. ch1 = cv->chars[(subwidth * y + x) * 2];
  469. attr1 = cv->attrs[(subwidth * y + x) * 2];
  470. ch2 = cv->chars[(subwidth * y + x) * 2 + 1];
  471. attr2 = cv->attrs[(subwidth * y + x) * 2 + 1];
  472. newchars[(subheight * x + subheight - 1 - y) * 2] = ch1;
  473. newattrs[(subheight * x + subheight - 1 - y) * 2] = attr1;
  474. newchars[(subheight * x + subheight - 1 - y) * 2 + 1] = ch2;
  475. newattrs[(subheight * x + subheight - 1 - y) * 2 + 1] = attr2;
  476. }
  477. }
  478. free(cv->chars);
  479. free(cv->attrs);
  480. /* Swap X and Y information */
  481. x = cv->frames[cv->frame].x;
  482. y = cv->frames[cv->frame].y;
  483. cv->frames[cv->frame].x = (cv->height - 1 - y) * 2;
  484. cv->frames[cv->frame].y = x / 2;
  485. x = cv->frames[cv->frame].handlex;
  486. y = cv->frames[cv->frame].handley;
  487. cv->frames[cv->frame].handlex = (cv->height - 1 - y) * 2;
  488. cv->frames[cv->frame].handley = x / 2;
  489. cv->frames[cv->frame].width = cv->height * 2;
  490. cv->frames[cv->frame].height = cv->width / 2;
  491. cv->frames[cv->frame].chars = newchars;
  492. cv->frames[cv->frame].attrs = newattrs;
  493. /* Reset the current frame shortcuts */
  494. _cucul_load_frame_info(cv);
  495. return 0;
  496. }
  497. /* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
  498. * of linear lookup. */
  499. static uint32_t flipchar(uint32_t ch)
  500. {
  501. int i;
  502. static uint32_t const noflip[] =
  503. {
  504. /* ASCII */
  505. ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
  506. 'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
  507. '_', 'i', 'o', 'v', 'w', 'x', '|',
  508. /* CP437 and box drawing */
  509. 0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
  510. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  511. 0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
  512. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  513. 0x2575, 0x2577, 0x2579, 0x257b, /* ╵ ╷ ╹ ╻ */
  514. 0
  515. };
  516. static uint32_t const pairs[] =
  517. {
  518. /* ASCII */
  519. '(', ')',
  520. '/', '\\',
  521. '<', '>',
  522. '[', ']',
  523. 'b', 'd',
  524. 'p', 'q',
  525. '{', '}',
  526. /* ASCII-Unicode */
  527. ';', 0x204f, /* ; ⁏ */
  528. '`', 0x00b4, /* ` ´ */
  529. ',', 0x02ce, /* , ˎ */
  530. 'C', 0x03fd, /* C Ͻ */
  531. 'E', 0x018e, /* E Ǝ */
  532. 'L', 0x2143, /* L ⅃ */
  533. 'N', 0x0418, /* N И */
  534. 'R', 0x042f, /* R Я */
  535. 'S', 0x01a7, /* S Ƨ */
  536. 'c', 0x0254, /* c ɔ */
  537. 'e', 0x0258, /* e ɘ */
  538. /* CP437 */
  539. 0x258c, 0x2590, /* ▌ ▐ */
  540. 0x2596, 0x2597, /* ▖ ▗ */
  541. 0x2598, 0x259d, /* ▘ ▝ */
  542. 0x2599, 0x259f, /* ▙ ▟ */
  543. 0x259a, 0x259e, /* ▚ ▞ */
  544. 0x259b, 0x259c, /* ▛ ▜ */
  545. 0x25ba, 0x25c4, /* ► ◄ */
  546. 0x2192, 0x2190, /* → ← */
  547. 0x2310, 0xac, /* ⌐ ¬ */
  548. /* Box drawing */
  549. 0x250c, 0x2510, /* ┌ ┐ */
  550. 0x2514, 0x2518, /* └ ┘ */
  551. 0x251c, 0x2524, /* ├ ┤ */
  552. 0x250f, 0x2513, /* ┏ ┓ */
  553. 0x2517, 0x251b, /* ┗ ┛ */
  554. 0x2523, 0x252b, /* ┣ ┫ */
  555. 0x2552, 0x2555, /* ╒ ╕ */
  556. 0x2558, 0x255b, /* ╘ ╛ */
  557. 0x2553, 0x2556, /* ╓ ╖ */
  558. 0x2559, 0x255c, /* ╙ ╜ */
  559. 0x2554, 0x2557, /* ╔ ╗ */
  560. 0x255a, 0x255d, /* ╚ ╝ */
  561. 0x255e, 0x2561, /* ╞ ╡ */
  562. 0x255f, 0x2562, /* ╟ ╢ */
  563. 0x2560, 0x2563, /* ╠ ╣ */
  564. 0x2574, 0x2576, /* ╴ ╶ */
  565. 0x2578, 0x257a, /* ╸ ╺ */
  566. 0
  567. };
  568. for(i = 0; noflip[i]; i++)
  569. if(ch == noflip[i])
  570. return ch;
  571. for(i = 0; pairs[i]; i++)
  572. if(ch == pairs[i])
  573. return pairs[i ^ 1];
  574. return ch;
  575. }
  576. static uint32_t flopchar(uint32_t ch)
  577. {
  578. int i;
  579. static uint32_t const noflop[] =
  580. {
  581. /* ASCII */
  582. ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
  583. '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
  584. 'c', 'o', '{', '|', '}',
  585. /* CP437 and box drawing */
  586. 0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
  587. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  588. 0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
  589. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  590. 0x2574, 0x2576, 0x2578, 0x257a, /* ╴ ╶ ╸ ╺ */
  591. 0
  592. };
  593. static uint32_t const pairs[] =
  594. {
  595. /* ASCII */
  596. '/', '\\',
  597. 'M', 'W',
  598. ',', '`',
  599. 'b', 'p',
  600. 'd', 'q',
  601. 'p', 'q',
  602. 'f', 't',
  603. '.', '\'',
  604. /* ASCII-Unicode */
  605. '_', 0x203e, /* _ ‾ */
  606. '!', 0x00a1, /* ! ¡ */
  607. 'L', 0x0413, /* L Г */
  608. 'N', 0x0418, /* N И */
  609. 'P', 0x042c, /* P Ь */
  610. 'R', 0x0281, /* R ʁ */
  611. 'S', 0x01a7, /* S Ƨ */
  612. 'U', 0x0548, /* U Ո */
  613. 'V', 0x039b, /* V Λ */
  614. 'Y', 0x2144, /* Y ⅄ */
  615. 'h', 0x03bc, /* h μ */
  616. 'i', 0x1d09, /* i ᴉ */
  617. 'v', 0x028c, /* v ʌ */
  618. 'w', 0x028d, /* w ʍ */
  619. 'y', 0x03bb, /* y λ */
  620. /* Not perfect, but better than nothing */
  621. '"', 0x201e, /* " „ */
  622. 'm', 0x026f, /* m ɯ */
  623. 'n', 'u',
  624. /* CP437 */
  625. 0x2584, 0x2580, /* ▄ ▀ */
  626. 0x2596, 0x2598, /* ▖ ▘ */
  627. 0x2597, 0x259d, /* ▗ ▝ */
  628. 0x2599, 0x259b, /* ▙ ▛ */
  629. 0x259f, 0x259c, /* ▟ ▜ */
  630. 0x259a, 0x259e, /* ▚ ▞ */
  631. /* Box drawing */
  632. 0x250c, 0x2514, /* ┌ └ */
  633. 0x2510, 0x2518, /* ┐ ┘ */
  634. 0x252c, 0x2534, /* ┬ ┴ */
  635. 0x250f, 0x2517, /* ┏ ┗ */
  636. 0x2513, 0x251b, /* ┓ ┛ */
  637. 0x2533, 0x253b, /* ┳ ┻ */
  638. 0x2554, 0x255a, /* ╔ ╚ */
  639. 0x2557, 0x255d, /* ╗ ╝ */
  640. 0x2566, 0x2569, /* ╦ ╩ */
  641. 0x2552, 0x2558, /* ╒ ╘ */
  642. 0x2555, 0x255b, /* ╕ ╛ */
  643. 0x2564, 0x2567, /* ╤ ╧ */
  644. 0x2553, 0x2559, /* ╓ ╙ */
  645. 0x2556, 0x255c, /* ╖ ╜ */
  646. 0x2565, 0x2568, /* ╥ ╨ */
  647. 0x2575, 0x2577, /* ╵ ╷ */
  648. 0x2579, 0x257b, /* ╹ ╻ */
  649. 0
  650. };
  651. for(i = 0; noflop[i]; i++)
  652. if(ch == noflop[i])
  653. return ch;
  654. for(i = 0; pairs[i]; i++)
  655. if(ch == pairs[i])
  656. return pairs[i ^ 1];
  657. return ch;
  658. }
  659. static uint32_t rotatechar(uint32_t ch)
  660. {
  661. int i;
  662. static uint32_t const norotate[] =
  663. {
  664. /* ASCII */
  665. ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
  666. 'O', 'S', 'X', 'Z', '\\', 'l', 'o', 's', 'x', 'z', '|',
  667. /* Unicode */
  668. 0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
  669. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  670. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  671. 0
  672. };
  673. static uint32_t const pairs[] =
  674. {
  675. /* ASCII */
  676. '(', ')',
  677. '<', '>',
  678. '[', ']',
  679. '{', '}',
  680. '.', '\'',
  681. '6', '9',
  682. 'M', 'W',
  683. 'b', 'q',
  684. 'd', 'p',
  685. 'n', 'u',
  686. /* ASCII-Unicode */
  687. '_', 0x203e, /* _ ‾ */
  688. ',', 0x00b4, /* , ´ */
  689. '`', 0x02ce, /* ` ˎ */
  690. '&', 0x214b, /* & ⅋ */
  691. '!', 0x00a1, /* ! ¡ */
  692. '?', 0x00bf, /* ? ¿ */
  693. 'C', 0x03fd, /* C Ͻ */
  694. 'E', 0x018e, /* E Ǝ */
  695. 'F', 0x2132, /* F Ⅎ */
  696. 'L', 0x2142, /* L ⅂ */
  697. 'U', 0x0548, /* U Ո */
  698. 'V', 0x039b, /* V Λ */
  699. 'Y', 0x2144, /* Y ⅄ */
  700. 'a', 0x0250, /* a ɐ */
  701. 'c', 0x0254, /* c ɔ */
  702. 'e', 0x0259, /* e ə */
  703. 'f', 0x025f, /* f ɟ */
  704. 'g', 0x1d77, /* g ᵷ */
  705. 'h', 0x0265, /* h ɥ */
  706. 'i', 0x1d09, /* i ᴉ */
  707. 'k', 0x029e, /* k ʞ */
  708. 'm', 0x026f, /* m ɯ */
  709. 'r', 0x0279, /* r ɹ */
  710. 't', 0x0287, /* t ʇ */
  711. 'v', 0x028c, /* v ʌ */
  712. 'w', 0x028d, /* w ʍ */
  713. 'y', 0x028e, /* y ʎ */
  714. /* Not perfect, but better than nothing */
  715. '"', 0x201e, /* " „ */
  716. /* Misc Unicode */
  717. 0x00e6, 0x1d02, /* æ ᴂ */
  718. 0x0153, 0x1d14, /* œ ᴔ */
  719. /* CP437 */
  720. 0x258c, 0x2590, /* ▌ ▐ */
  721. 0x2584, 0x2580, /* ▄ ▀ */
  722. 0x2596, 0x259d, /* ▖ ▝ */
  723. 0x2597, 0x2598, /* ▗ ▘ */
  724. 0x2599, 0x259c, /* ▙ ▜ */
  725. 0x259f, 0x259b, /* ▟ ▛ */
  726. /* Box drawing */
  727. 0x250c, 0x2518, /* ┌ ┘ */
  728. 0x2510, 0x2514, /* ┐ └ */
  729. 0x251c, 0x2524, /* ├ ┤ */
  730. 0x252c, 0x2534, /* ┬ ┴ */
  731. 0x250f, 0x251b, /* ┏ ┛ */
  732. 0x2513, 0x2517, /* ┓ ┗ */
  733. 0x2523, 0x252b, /* ┣ ┫ */
  734. 0x2533, 0x253b, /* ┳ ┻ */
  735. 0x2554, 0x255d, /* ╔ ╝ */
  736. 0x2557, 0x255a, /* ╗ ╚ */
  737. 0x2560, 0x2563, /* ╠ ╣ */
  738. 0x2566, 0x2569, /* ╦ ╩ */
  739. 0x2552, 0x255b, /* ╒ ╛ */
  740. 0x2555, 0x2558, /* ╕ ╘ */
  741. 0x255e, 0x2561, /* ╞ ╡ */
  742. 0x2564, 0x2567, /* ╤ ╧ */
  743. 0x2553, 0x255c, /* ╓ ╜ */
  744. 0x2556, 0x2559, /* ╖ ╙ */
  745. 0x255f, 0x2562, /* ╟ ╢ */
  746. 0x2565, 0x2568, /* ╥ ╨ */
  747. 0x2574, 0x2576, /* ╴ ╶ */
  748. 0x2575, 0x2577, /* ╵ ╷ */
  749. 0x2578, 0x257a, /* ╸ ╺ */
  750. 0x2579, 0x257b, /* ╹ ╻ */
  751. 0
  752. };
  753. for(i = 0; norotate[i]; i++)
  754. if(ch == norotate[i])
  755. return ch;
  756. for(i = 0; pairs[i]; i++)
  757. if(ch == pairs[i])
  758. return pairs[i ^ 1];
  759. return ch;
  760. }
  761. static uint32_t const leftright2[] =
  762. {
  763. /* ASCII */
  764. '/', '\\',
  765. '|', '-',
  766. '|', '_', /* This is all right because there was already a '|' before */
  767. /* ASCII-Unicode */
  768. '|', 0x203e, /* | ‾ */
  769. /* Misc Unicode */
  770. 0x2571, 0x2572, /* ╱ ╲ */
  771. /* Box drawing */
  772. 0x2500, 0x2502, /* ─ │ */
  773. 0x2501, 0x2503, /* ━ ┃ */
  774. 0x2550, 0x2551, /* ═ ║ */
  775. 0, 0
  776. };
  777. static uint32_t const leftright4[] =
  778. {
  779. /* ASCII */
  780. '<', 'v', '>', '^',
  781. ',', '.', '\'', '`',
  782. /* Misc Unicode */
  783. 0x256d, 0x2570, 0x256f, 0x256e, /* ╭ ╰ ╯ ╮ */
  784. /* CP437 */
  785. 0x258c, 0x2584, 0x2590, 0x2580, /* ▌ ▄ ▐ ▀ */
  786. 0x2596, 0x2597, 0x259d, 0x2598, /* ▖ ▗ ▝ ▘ */
  787. 0x2599, 0x259f, 0x259c, 0x259b, /* ▙ ▟ ▜ ▛ */
  788. /* Box drawing */
  789. 0x250c, 0x2514, 0x2518, 0x2510, /* ┌ └ ┘ ┐ */
  790. 0x250f, 0x2517, 0x251b, 0x2513, /* ┏ ┗ ┛ ┓ */
  791. 0x251c, 0x2534, 0x2524, 0x252c, /* ├ ┴ ┤ ┬ */
  792. 0x2523, 0x253b, 0x252b, 0x2533, /* ┣ ┻ ┫ ┳ */
  793. 0x2552, 0x2559, 0x255b, 0x2556, /* ╒ ╙ ╛ ╖ */
  794. 0x2553, 0x2558, 0x255c, 0x2555, /* ╓ ╘ ╜ ╕ */
  795. 0x2554, 0x255a, 0x255d, 0x2557, /* ╔ ╚ ╝ ╗ */
  796. 0x255e, 0x2568, 0x2561, 0x2565, /* ╞ ╨ ╡ ╥ */
  797. 0x255f, 0x2567, 0x2562, 0x2564, /* ╟ ╧ ╢ ╤ */
  798. 0x2560, 0x2569, 0x2563, 0x2566, /* ╠ ╩ ╣ ╦ */
  799. 0x2574, 0x2577, 0x2576, 0x2575, /* ╴ ╷ ╶ ╵ */
  800. 0x2578, 0x257b, 0x257a, 0x2579, /* ╸ ╻ ╺ ╹ */
  801. 0, 0, 0, 0
  802. };
  803. static uint32_t leftchar(uint32_t ch)
  804. {
  805. int i;
  806. for(i = 0; leftright2[i]; i++)
  807. if(ch == leftright2[i])
  808. return leftright2[(i & ~1) | ((i + 1) & 1)];
  809. for(i = 0; leftright4[i]; i++)
  810. if(ch == leftright4[i])
  811. return leftright4[(i & ~3) | ((i + 1) & 3)];
  812. return ch;
  813. }
  814. static uint32_t rightchar(uint32_t ch)
  815. {
  816. int i;
  817. for(i = 0; leftright2[i]; i++)
  818. if(ch == leftright2[i])
  819. return leftright2[(i & ~1) | ((i - 1) & 1)];
  820. for(i = 0; leftright4[i]; i++)
  821. if(ch == leftright4[i])
  822. return leftright4[(i & ~3) | ((i - 1) & 3)];
  823. return ch;
  824. }