You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2012 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://sam.zoy.org/wtfpl/COPYING for more details.
  11. */
  12. /*
  13. * This file contains various canvas handling functions such as character
  14. * and string drawing.
  15. */
  16. #include "config.h"
  17. #if !defined(__KERNEL__)
  18. # include <stdio.h> /* BUFSIZ */
  19. # include <string.h>
  20. # include <stdlib.h>
  21. # include <stdarg.h>
  22. # if defined(HAVE_UNISTD_H)
  23. # include <unistd.h>
  24. # endif
  25. # if defined(HAVE_SIGNAL_H)
  26. # include <signal.h>
  27. # endif
  28. # if defined(HAVE_SYS_IOCTL_H)
  29. # include <sys/ioctl.h>
  30. # endif
  31. #endif
  32. #include "caca.h"
  33. #include "caca_internals.h"
  34. #if defined _WIN32 && defined __GNUC__ && __GNUC__ >= 3
  35. int vsnprintf_s(char *s, size_t n, size_t c,
  36. const char *fmt, va_list ap) CACA_WEAK;
  37. int vsnprintf(char *s, size_t n, const char *fmt, va_list ap) CACA_WEAK;
  38. #endif
  39. /** \brief Set cursor position.
  40. *
  41. * Put the cursor at the given coordinates. Functions making use of the
  42. * cursor will use the new values. Setting the cursor position outside the
  43. * canvas is legal but the cursor will not be shown.
  44. *
  45. * This function never fails.
  46. *
  47. * \param cv A handle to the libcaca canvas.
  48. * \param x X cursor coordinate.
  49. * \param y Y cursor coordinate.
  50. * \return This function always returns 0.
  51. */
  52. int caca_gotoxy(caca_canvas_t *cv, int x, int y)
  53. {
  54. cv->frames[cv->frame].x = x;
  55. cv->frames[cv->frame].y = y;
  56. return 0;
  57. }
  58. /** \brief Get X cursor position.
  59. *
  60. * Retrieve the X coordinate of the cursor's position.
  61. *
  62. * This function never fails.
  63. *
  64. * \param cv A handle to the libcaca canvas.
  65. * \return The cursor's X coordinate.
  66. */
  67. int caca_wherex(caca_canvas_t const *cv)
  68. {
  69. return cv->frames[cv->frame].x;
  70. }
  71. /** \brief Get Y cursor position.
  72. *
  73. * Retrieve the Y coordinate of the cursor's position.
  74. *
  75. * This function never fails.
  76. *
  77. * \param cv A handle to the libcaca canvas.
  78. * \return The cursor's Y coordinate.
  79. */
  80. int caca_wherey(caca_canvas_t const *cv)
  81. {
  82. return cv->frames[cv->frame].y;
  83. }
  84. /** \brief Print an ASCII or Unicode character.
  85. *
  86. * Print an ASCII or Unicode character at the given coordinates, using
  87. * the default foreground and background colour values.
  88. *
  89. * If the coordinates are outside the canvas boundaries, nothing is printed.
  90. * If a fullwidth Unicode character gets overwritten, its remaining visible
  91. * parts are replaced with spaces. If the canvas' boundaries would split the
  92. * fullwidth character in two, a space is printed instead.
  93. *
  94. * The behaviour when printing non-printable characters or invalid UTF-32
  95. * characters is undefined. To print a sequence of bytes forming an UTF-8
  96. * character instead of an UTF-32 character, use the caca_put_str() function.
  97. *
  98. * This function returns the width of the printed character. If it is a
  99. * fullwidth character, 2 is returned. Otherwise, 1 is returned.
  100. *
  101. * This function never fails.
  102. *
  103. * \param cv A handle to the libcaca canvas.
  104. * \param x X coordinate.
  105. * \param y Y coordinate.
  106. * \param ch The character to print.
  107. * \return The width of the printed character: 2 for a fullwidth character,
  108. * 1 otherwise.
  109. */
  110. int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch)
  111. {
  112. uint32_t *curchar, *curattr, attr;
  113. int fullwidth, xmin, xmax, ret;
  114. if(ch == CACA_MAGIC_FULLWIDTH)
  115. return 1;
  116. fullwidth = caca_utf32_is_fullwidth(ch);
  117. ret = fullwidth ? 2 : 1;
  118. if(x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  119. return ret;
  120. if(x == -1 && fullwidth)
  121. {
  122. x = 0;
  123. ch = ' ';
  124. fullwidth = 0;
  125. }
  126. else if(x < 0)
  127. return ret;
  128. curchar = cv->chars + x + y * cv->width;
  129. curattr = cv->attrs + x + y * cv->width;
  130. attr = cv->curattr;
  131. xmin = xmax = x;
  132. /* When overwriting the right part of a fullwidth character,
  133. * replace its left part with a space. */
  134. if(x && curchar[0] == CACA_MAGIC_FULLWIDTH)
  135. {
  136. curchar[-1] = ' ';
  137. xmin--;
  138. }
  139. if(fullwidth)
  140. {
  141. if(x + 1 == (int)cv->width)
  142. ch = ' ';
  143. else
  144. {
  145. xmax++;
  146. /* When overwriting the left part of a fullwidth character,
  147. * replace its right part with a space. */
  148. if(x + 2 < (int)cv->width && curchar[2] == CACA_MAGIC_FULLWIDTH)
  149. {
  150. curchar[2] = ' ';
  151. xmax++;
  152. }
  153. curchar[1] = CACA_MAGIC_FULLWIDTH;
  154. curattr[1] = attr;
  155. }
  156. }
  157. else
  158. {
  159. /* When overwriting the left part of a fullwidth character,
  160. * replace its right part with a space. */
  161. if(x + 1 != (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH)
  162. {
  163. curchar[1] = ' ';
  164. xmax++;
  165. }
  166. }
  167. /* Only add a dirty rectangle if we are pasting a different character
  168. * or attribute at that place. This does not account for inconsistencies
  169. * in the canvas, ie. if CACA_MAGIC_FULLWIDTH lies at illegal places,
  170. * but it's the caller's responsibility not to corrupt the contents. */
  171. if(!cv->dirty_disabled
  172. && (curchar[0] != ch || curattr[0] != attr))
  173. caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1);
  174. curchar[0] = ch;
  175. curattr[0] = attr;
  176. return ret;
  177. }
  178. /** \brief Get the Unicode character at the given coordinates.
  179. *
  180. * Get the ASCII or Unicode value of the character at the given
  181. * coordinates. If the value is less or equal to 127 (0x7f),
  182. * the character can be printed as ASCII. Otherise, it must be handled
  183. * as a UTF-32 value.
  184. *
  185. * If the coordinates are outside the canvas boundaries, a space (0x20)
  186. * is returned.
  187. *
  188. * A special exception is when CACA_MAGIC_FULLWIDTH is returned. This
  189. * value is guaranteed not to be a valid Unicode character, and indicates
  190. * that the character at the left of the requested one is a fullwidth
  191. * character.
  192. *
  193. * This function never fails.
  194. *
  195. * \param cv A handle to the libcaca canvas.
  196. * \param x X coordinate.
  197. * \param y Y coordinate.
  198. * \return The Unicode character at the given coordinates.
  199. */
  200. uint32_t caca_get_char(caca_canvas_t const *cv, int x, int y)
  201. {
  202. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  203. return ' ';
  204. return cv->chars[x + y * cv->width];
  205. }
  206. /** \brief Print a string.
  207. *
  208. * Print an UTF-8 string at the given coordinates, using the default
  209. * foreground and background values. The coordinates may be outside the
  210. * canvas boundaries (eg. a negative Y coordinate) and the string will
  211. * be cropped accordingly if it is too long.
  212. *
  213. * See caca_put_char() for more information on how fullwidth characters
  214. * are handled when overwriting each other or at the canvas' boundaries.
  215. *
  216. * This function returns the number of cells printed by the string. It is
  217. * not the number of characters printed, because fullwidth characters
  218. * account for two cells.
  219. *
  220. * This function never fails.
  221. *
  222. * \param cv A handle to the libcaca canvas.
  223. * \param x X coordinate.
  224. * \param y Y coordinate.
  225. * \param s The string to print.
  226. * \return The number of cells printed.
  227. */
  228. int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s)
  229. {
  230. size_t rd;
  231. int len = 0;
  232. if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
  233. {
  234. while(*s)
  235. {
  236. len += caca_utf32_is_fullwidth(caca_utf8_to_utf32(s, &rd)) ? 2 : 1;
  237. s += rd;
  238. }
  239. return len;
  240. }
  241. while(*s)
  242. {
  243. uint32_t ch = caca_utf8_to_utf32(s, &rd);
  244. if(x + len >= -1 && x + len < (int)cv->width)
  245. caca_put_char(cv, x + len, y, ch);
  246. len += caca_utf32_is_fullwidth(ch) ? 2 : 1;
  247. s += rd;
  248. }
  249. return len;
  250. }
  251. /** \brief Print a formated string.
  252. *
  253. * Format a string at the given coordinates, using the default foreground
  254. * and background values. The coordinates may be outside the canvas
  255. * boundaries (eg. a negative Y coordinate) and the string will be cropped
  256. * accordingly if it is too long. The syntax of the format string is the
  257. * same as for the C printf() function.
  258. *
  259. * This function returns the number of cells printed by the string. It is
  260. * not the number of characters printed, because fullwidth characters
  261. * account for two cells.
  262. *
  263. * This function never fails.
  264. *
  265. * \param cv A handle to the libcaca canvas.
  266. * \param x X coordinate.
  267. * \param y Y coordinate.
  268. * \param format The format string to print.
  269. * \param ... Arguments to the format string.
  270. * \return The number of cells printed.
  271. */
  272. int caca_printf(caca_canvas_t *cv, int x, int y, char const *format, ...)
  273. {
  274. va_list args;
  275. int ret;
  276. va_start(args, format);
  277. ret = caca_vprintf(cv, x, y, format, args);
  278. va_end(args);
  279. return ret;
  280. }
  281. /** \brief Print a formated string (va_list version).
  282. *
  283. * Format a string at the given coordinates, using the default foreground
  284. * and background values. The coordinates may be outside the canvas
  285. * boundaries (eg. a negative X coordinate) and the string will be cropped
  286. * accordingly if it is too long. The syntax of the format string is the
  287. * same as for the C vprintf() function.
  288. *
  289. * This function returns the number of cells printed by the string. It is
  290. * not the number of characters printed, because fullwidth characters
  291. * account for two cells.
  292. *
  293. * This function never fails.
  294. *
  295. * \param cv A handle to the libcaca canvas.
  296. * \param x X coordinate.
  297. * \param y Y coordinate.
  298. * \param format The format string to print.
  299. * \param args A va_list containting the arguments to the format string.
  300. * \return The number of cells printed.
  301. */
  302. int caca_vprintf(caca_canvas_t *cv, int x, int y, char const *format,
  303. va_list args)
  304. {
  305. char tmp[BUFSIZ];
  306. char *buf = tmp;
  307. int bufsize = BUFSIZ, ret;
  308. if(cv->width - x + 1 > BUFSIZ)
  309. {
  310. bufsize = cv->width - x + 1;
  311. buf = malloc(bufsize);
  312. }
  313. #if defined(HAVE_VSNPRINTF_S)
  314. vsnprintf_s(buf, bufsize, _TRUNCATE, format, args);
  315. #elif defined(HAVE_VSNPRINTF)
  316. vsnprintf(buf, bufsize, format, args);
  317. #else
  318. vsprintf(buf, format, args);
  319. #endif
  320. buf[bufsize - 1] = '\0';
  321. ret = caca_put_str(cv, x, y, buf);
  322. if(buf != tmp)
  323. free(buf);
  324. return ret;
  325. }
  326. /** \brief Clear the canvas.
  327. *
  328. * Clear the canvas using the current foreground and background colours.
  329. *
  330. * This function never fails.
  331. *
  332. * \param cv The canvas to clear.
  333. * \return This function always returns 0.
  334. */
  335. int caca_clear_canvas(caca_canvas_t *cv)
  336. {
  337. uint32_t attr = cv->curattr;
  338. int n;
  339. for(n = cv->width * cv->height; n--; )
  340. {
  341. cv->chars[n] = (uint32_t)' ';
  342. cv->attrs[n] = attr;
  343. }
  344. if(!cv->dirty_disabled)
  345. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  346. return 0;
  347. }
  348. /** \brief Set cursor handle.
  349. *
  350. * Set the canvas' handle. Blitting functions will use the handle value
  351. * to put the canvas at the proper coordinates.
  352. *
  353. * This function never fails.
  354. *
  355. * \param cv A handle to the libcaca canvas.
  356. * \param x X handle coordinate.
  357. * \param y Y handle coordinate.
  358. * \return This function always returns 0.
  359. */
  360. int caca_set_canvas_handle(caca_canvas_t *cv, int x, int y)
  361. {
  362. cv->frames[cv->frame].handlex = x;
  363. cv->frames[cv->frame].handley = y;
  364. return 0;
  365. }
  366. /** \brief Get X handle position.
  367. *
  368. * Retrieve the X coordinate of the canvas' handle.
  369. *
  370. * This function never fails.
  371. *
  372. * \param cv A handle to the libcaca canvas.
  373. * \return The canvas' handle's X coordinate.
  374. */
  375. int caca_get_canvas_handle_x(caca_canvas_t const *cv)
  376. {
  377. return cv->frames[cv->frame].handlex;
  378. }
  379. /** \brief Get Y handle position.
  380. *
  381. * Retrieve the Y coordinate of the canvas' handle.
  382. *
  383. * This function never fails.
  384. *
  385. * \param cv A handle to the libcaca canvas.
  386. * \return The canvas' handle's Y coordinate.
  387. */
  388. int caca_get_canvas_handle_y(caca_canvas_t const *cv)
  389. {
  390. return cv->frames[cv->frame].handley;
  391. }
  392. /** \brief Blit a canvas onto another one.
  393. *
  394. * Blit a canvas onto another one at the given coordinates.
  395. * An optional mask canvas can be used.
  396. *
  397. * If an error occurs, -1 is returned and \b errno is set accordingly:
  398. * - \c EINVAL A mask was specified but the mask size and source canvas
  399. * size do not match.
  400. *
  401. * \param dst The destination canvas.
  402. * \param x X coordinate.
  403. * \param y Y coordinate.
  404. * \param src The source canvas.
  405. * \param mask The mask canvas.
  406. * \return 0 in case of success, -1 if an error occurred.
  407. */
  408. int caca_blit(caca_canvas_t *dst, int x, int y,
  409. caca_canvas_t const *src, caca_canvas_t const *mask)
  410. {
  411. int i, j, starti, startj, endi, endj, stride, bleed_left, bleed_right;
  412. if(mask && (src->width != mask->width || src->height != mask->height))
  413. {
  414. seterrno(EINVAL);
  415. return -1;
  416. }
  417. x -= src->frames[src->frame].handlex;
  418. y -= src->frames[src->frame].handley;
  419. starti = x < 0 ? -x : 0;
  420. startj = y < 0 ? -y : 0;
  421. endi = (x + src->width >= dst->width) ? dst->width - x : src->width;
  422. endj = (y + src->height >= dst->height) ? dst->height - y : src->height;
  423. stride = endi - starti;
  424. if(starti > src->width || startj > src->height
  425. || starti >= endi || startj >= endj)
  426. return 0;
  427. bleed_left = bleed_right = 0;
  428. for(j = startj; j < endj; j++)
  429. {
  430. int dstix = (j + y) * dst->width + starti + x;
  431. int srcix = j * src->width + starti;
  432. /* FIXME: we are ignoring the mask here */
  433. if((starti + x) && dst->chars[dstix] == CACA_MAGIC_FULLWIDTH)
  434. {
  435. dst->chars[dstix - 1] = ' ';
  436. bleed_left = 1;
  437. }
  438. if(endi + x < dst->width
  439. && dst->chars[dstix + stride] == CACA_MAGIC_FULLWIDTH)
  440. {
  441. dst->chars[dstix + stride] = ' ';
  442. bleed_right = 1;
  443. }
  444. if(mask)
  445. {
  446. for(i = 0; i < stride; i++)
  447. {
  448. if(mask->chars[srcix + i] == (uint32_t)' ')
  449. continue;
  450. if(dst->chars[dstix + i] != src->chars[srcix + i] ||
  451. dst->attrs[dstix + i] != src->attrs[srcix + i])
  452. {
  453. dst->chars[dstix + i] = src->chars[srcix + i];
  454. dst->attrs[dstix + i] = src->attrs[srcix + i];
  455. if(!dst->dirty_disabled)
  456. caca_add_dirty_rect(dst, x + starti + i, y + j, 1, 1);
  457. }
  458. }
  459. }
  460. else
  461. {
  462. if(memcmp(dst->chars + dstix, src->chars + srcix, stride * 4) ||
  463. memcmp(dst->attrs + dstix, src->attrs + srcix, stride * 4))
  464. {
  465. /* FIXME be more precise ? */
  466. memcpy(dst->chars + dstix, src->chars + srcix, stride * 4);
  467. memcpy(dst->attrs + dstix, src->attrs + srcix, stride * 4);
  468. if(!dst->dirty_disabled)
  469. caca_add_dirty_rect(dst, x + starti, y + j, stride, 1);
  470. }
  471. }
  472. /* Fix split fullwidth chars */
  473. if(src->chars[srcix] == CACA_MAGIC_FULLWIDTH)
  474. dst->chars[dstix] = ' ';
  475. if(endi < src->width && src->chars[endi] == CACA_MAGIC_FULLWIDTH)
  476. dst->chars[dstix + stride - 1] = ' ';
  477. }
  478. return 0;
  479. }
  480. /** \brief Set a canvas' new boundaries.
  481. *
  482. * Set new boundaries for a canvas. This function can be used to crop a
  483. * canvas, to expand it or for combinations of both actions. All frames
  484. * are affected by this function.
  485. *
  486. * If an error occurs, -1 is returned and \b errno is set accordingly:
  487. * - \c EINVAL Specified width or height is invalid.
  488. * - \c EBUSY The canvas is in use by a display driver and cannot be resized.
  489. * - \c ENOMEM Not enough memory for the requested canvas size. If this
  490. * happens, the canvas handle becomes invalid and should not be used.
  491. *
  492. * \param cv The canvas to crop.
  493. * \param x X coordinate of the top-left corner.
  494. * \param y Y coordinate of the top-left corner.
  495. * \param w The width of the cropped area.
  496. * \param h The height of the cropped area.
  497. * \return 0 in case of success, -1 if an error occurred.
  498. */
  499. int caca_set_canvas_boundaries(caca_canvas_t *cv, int x, int y, int w, int h)
  500. {
  501. caca_canvas_t *new;
  502. int f, saved_f, framecount;
  503. if(cv->refcount)
  504. {
  505. seterrno(EBUSY);
  506. return -1;
  507. }
  508. if(w < 0 || h < 0)
  509. {
  510. seterrno(EINVAL);
  511. return -1;
  512. }
  513. new = caca_create_canvas(w, h);
  514. framecount = caca_get_frame_count(cv);
  515. saved_f = cv->frame;
  516. for(f = 0; f < framecount; f++)
  517. {
  518. if(f)
  519. caca_create_frame(new, framecount);
  520. caca_set_frame(cv, f);
  521. caca_set_frame(new, f);
  522. caca_blit(new, -x, -y, cv, NULL);
  523. free(cv->frames[f].chars);
  524. free(cv->frames[f].attrs);
  525. }
  526. free(cv->frames);
  527. cv->frames = new->frames;
  528. free(new);
  529. caca_set_frame(cv, saved_f);
  530. _caca_load_frame_info(cv);
  531. /* FIXME: this may be optimised somewhat */
  532. if(!cv->dirty_disabled)
  533. caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
  534. return 0;
  535. }
  536. /*
  537. * Functions for the mingw32 runtime
  538. */
  539. #if defined _WIN32 && defined __GNUC__ && __GNUC__ >= 3
  540. int vsnprintf_s(char *s, size_t n, size_t c, const char *fmt, va_list ap)
  541. {
  542. return vsnprintf(s, n, fmt, ap);
  543. }
  544. int vsnprintf(char *s, size_t n, const char *fmt, va_list ap)
  545. {
  546. return 0;
  547. }
  548. #endif
  549. /*
  550. * XXX: The following functions are aliases.
  551. */
  552. int cucul_gotoxy(cucul_canvas_t *, int, int) CACA_ALIAS(caca_gotoxy);
  553. int cucul_get_cursor_x(cucul_canvas_t const *) CACA_ALIAS(caca_wherex);
  554. int cucul_get_cursor_y(cucul_canvas_t const *) CACA_ALIAS(caca_wherey);
  555. int caca_get_cursor_x(caca_canvas_t const *) CACA_ALIAS(caca_wherex);
  556. int caca_get_cursor_y(caca_canvas_t const *) CACA_ALIAS(caca_wherey);
  557. int cucul_put_char(cucul_canvas_t *, int, int, uint32_t)
  558. CACA_ALIAS(caca_put_char);
  559. uint32_t cucul_get_char(cucul_canvas_t const *, int, int)
  560. CACA_ALIAS(caca_get_char);
  561. int cucul_put_str(cucul_canvas_t *, int, int, char const *)
  562. CACA_ALIAS(caca_put_str);
  563. int cucul_printf(cucul_canvas_t *, int, int, char const *, ...)
  564. CACA_ALIAS(caca_printf);
  565. int cucul_clear_canvas(cucul_canvas_t *) CACA_ALIAS(caca_clear_canvas);
  566. int cucul_set_canvas_handle(cucul_canvas_t *, int, int)
  567. CACA_ALIAS(caca_set_canvas_handle);
  568. int cucul_get_canvas_handle_x(cucul_canvas_t const *)
  569. CACA_ALIAS(caca_get_canvas_handle_x);
  570. int cucul_get_canvas_handle_y(cucul_canvas_t const *)
  571. CACA_ALIAS(caca_get_canvas_handle_y);
  572. int cucul_blit(cucul_canvas_t *, int, int, cucul_canvas_t const *,
  573. cucul_canvas_t const *) CACA_ALIAS(caca_blit);
  574. int cucul_set_canvas_boundaries(cucul_canvas_t *, int, int, int, int)
  575. CACA_ALIAS(caca_set_canvas_boundaries);