Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

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