Browse Source

* Completed return value and errno handling in libcucul API.

tags/v0.99.beta14
Sam Hocevar sam 18 years ago
parent
commit
0a53a92195
7 changed files with 642 additions and 327 deletions
  1. +22
    -22
      cucul/cucul.h
  2. +174
    -42
      cucul/dither.c
  3. +21
    -0
      cucul/export.c
  4. +72
    -4
      cucul/font.c
  5. +284
    -249
      cucul/import.c
  6. +45
    -6
      cucul/sprite.c
  7. +24
    -4
      cucul/transform.c

+ 22
- 22
cucul/cucul.h View File

@@ -112,10 +112,10 @@ int cucul_blit(cucul_canvas_t *, int, int, cucul_canvas_t const *, cucul_canvas_
* These functions perform horizontal and vertical canvas flipping. * These functions perform horizontal and vertical canvas flipping.
* *
* @{ */ * @{ */
void cucul_invert(cucul_canvas_t *);
void cucul_flip(cucul_canvas_t *);
void cucul_flop(cucul_canvas_t *);
void cucul_rotate(cucul_canvas_t *);
int cucul_invert(cucul_canvas_t *);
int cucul_flip(cucul_canvas_t *);
int cucul_flop(cucul_canvas_t *);
int cucul_rotate(cucul_canvas_t *);
/* @} */ /* @} */


/** \defgroup prim libcucul primitives drawing /** \defgroup prim libcucul primitives drawing
@@ -150,9 +150,9 @@ int cucul_fill_triangle(cucul_canvas_t *, int, int, int, int, int, int, char con
* *
* @{ */ * @{ */
unsigned int cucul_get_canvas_frame_count(cucul_canvas_t *); unsigned int cucul_get_canvas_frame_count(cucul_canvas_t *);
void cucul_set_canvas_frame(cucul_canvas_t *, unsigned int);
void cucul_create_canvas_frame(cucul_canvas_t *, unsigned int);
void cucul_free_canvas_frame(cucul_canvas_t *, unsigned int);
int cucul_set_canvas_frame(cucul_canvas_t *, unsigned int);
int cucul_create_canvas_frame(cucul_canvas_t *, unsigned int);
int cucul_free_canvas_frame(cucul_canvas_t *, unsigned int);
/* @} */ /* @} */


/** \defgroup dither libcucul bitmap dithering /** \defgroup dither libcucul bitmap dithering
@@ -165,24 +165,24 @@ cucul_dither_t *cucul_create_dither(unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int); unsigned int, unsigned int);
void cucul_set_dither_palette(cucul_dither_t *,
unsigned int r[], unsigned int g[],
unsigned int b[], unsigned int a[]);
void cucul_set_dither_brightness(cucul_dither_t *, float);
void cucul_set_dither_gamma(cucul_dither_t *, float);
void cucul_set_dither_contrast(cucul_dither_t *, float);
void cucul_set_dither_invert(cucul_dither_t *, int);
void cucul_set_dither_antialias(cucul_dither_t *, char const *);
int cucul_set_dither_palette(cucul_dither_t *,
unsigned int r[], unsigned int g[],
unsigned int b[], unsigned int a[]);
int cucul_set_dither_brightness(cucul_dither_t *, float);
int cucul_set_dither_gamma(cucul_dither_t *, float);
int cucul_set_dither_contrast(cucul_dither_t *, float);
int cucul_set_dither_invert(cucul_dither_t *, int);
int cucul_set_dither_antialias(cucul_dither_t *, char const *);
char const * const * cucul_get_dither_antialias_list(cucul_dither_t const *); char const * const * cucul_get_dither_antialias_list(cucul_dither_t const *);
void cucul_set_dither_color(cucul_dither_t *, char const *);
int cucul_set_dither_color(cucul_dither_t *, char const *);
char const * const * cucul_get_dither_color_list(cucul_dither_t const *); char const * const * cucul_get_dither_color_list(cucul_dither_t const *);
void cucul_set_dither_charset(cucul_dither_t *, char const *);
int cucul_set_dither_charset(cucul_dither_t *, char const *);
char const * const * cucul_get_dither_charset_list(cucul_dither_t const *); char const * const * cucul_get_dither_charset_list(cucul_dither_t const *);
void cucul_set_dither_mode(cucul_dither_t *, char const *);
int cucul_set_dither_mode(cucul_dither_t *, char const *);
char const * const * cucul_get_dither_mode_list(cucul_dither_t const *); char const * const * cucul_get_dither_mode_list(cucul_dither_t const *);
void cucul_dither_bitmap(cucul_canvas_t *, int, int, int, int,
int cucul_dither_bitmap(cucul_canvas_t *, int, int, int, int,
cucul_dither_t const *, void *); cucul_dither_t const *, void *);
void cucul_free_dither(cucul_dither_t *);
int cucul_free_dither(cucul_dither_t *);
/* @} */ /* @} */


/** \defgroup font libcucul font handling /** \defgroup font libcucul font handling
@@ -195,9 +195,9 @@ cucul_font_t *cucul_load_font(void const *, unsigned int);
char const * const * cucul_get_font_list(void); char const * const * cucul_get_font_list(void);
unsigned int cucul_get_font_width(cucul_font_t *); unsigned int cucul_get_font_width(cucul_font_t *);
unsigned int cucul_get_font_height(cucul_font_t *); unsigned int cucul_get_font_height(cucul_font_t *);
void cucul_render_canvas(cucul_canvas_t *, cucul_font_t *, void *,
int cucul_render_canvas(cucul_canvas_t *, cucul_font_t *, void *,
unsigned int, unsigned int, unsigned int); unsigned int, unsigned int, unsigned int);
void cucul_free_font(cucul_font_t *);
int cucul_free_font(cucul_font_t *);
/* @} */ /* @} */


/** \defgroup importexport libcucul importers/exporters from/to various formats /** \defgroup importexport libcucul importers/exporters from/to various formats


+ 174
- 42
cucul/dither.c View File

@@ -26,6 +26,9 @@
# include <stdlib.h> # include <stdlib.h>
# include <limits.h> # include <limits.h>
# include <string.h> # include <string.h>
# if defined(HAVE_ERRNO_H)
# include <errno.h>
# endif
#endif #endif


#include "cucul.h" #include "cucul.h"
@@ -236,6 +239,11 @@ static inline void rgb2hsv_default(int r, int g, int b,
* cucul_set_dither_palette() function. For depths greater than 8 bits per * cucul_set_dither_palette() function. For depths greater than 8 bits per
* pixel, a zero alpha mask causes the alpha values to be ignored. * pixel, a zero alpha mask causes the alpha values to be ignored.
* *
* If an error occurs, NULL is returned and \b errno is set accordingly:
* - \c EINVAL Requested width, height, pitch or bits per pixel value was
* invalid.
* - \c ENOMEM Not enough memory to allocate dither structure.
*
* \param bpp Bitmap depth in bits per pixel. * \param bpp Bitmap depth in bits per pixel.
* \param w Bitmap width in pixels. * \param w Bitmap width in pixels.
* \param h Bitmap height in pixels. * \param h Bitmap height in pixels.
@@ -244,7 +252,7 @@ static inline void rgb2hsv_default(int r, int g, int b,
* \param gmask Bitmask for green values. * \param gmask Bitmask for green values.
* \param bmask Bitmask for blue values. * \param bmask Bitmask for blue values.
* \param amask Bitmask for alpha values. * \param amask Bitmask for alpha values.
* \return Dither object, or NULL upon error.
* \return Dither object upon success, NULL if an error occurred.
*/ */
cucul_dither_t *cucul_create_dither(unsigned int bpp, unsigned int w, cucul_dither_t *cucul_create_dither(unsigned int bpp, unsigned int w,
unsigned int h, unsigned int pitch, unsigned int h, unsigned int pitch,
@@ -256,11 +264,21 @@ cucul_dither_t *cucul_create_dither(unsigned int bpp, unsigned int w,


/* Minor sanity test */ /* Minor sanity test */
if(!w || !h || !pitch || bpp > 32 || bpp < 8) if(!w || !h || !pitch || bpp > 32 || bpp < 8)
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL; return NULL;
}


d = malloc(sizeof(cucul_dither_t)); d = malloc(sizeof(cucul_dither_t));
if(!d) if(!d)
{
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL; return NULL;
}


d->bpp = bpp; d->bpp = bpp;
d->has_palette = 0; d->has_palette = 0;
@@ -325,99 +343,142 @@ cucul_dither_t *cucul_create_dither(unsigned int bpp, unsigned int w,
* Set the palette of an 8 bits per pixel bitmap. Values should be between * Set the palette of an 8 bits per pixel bitmap. Values should be between
* 0 and 4095 (0xfff). * 0 and 4095 (0xfff).
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Dither bits per pixel value is not 8, or one of the pixel
* values was outside the range 0 - 4095.
*
* \param d Dither object. * \param d Dither object.
* \param red Array of 256 red values. * \param red Array of 256 red values.
* \param green Array of 256 green values. * \param green Array of 256 green values.
* \param blue Array of 256 blue values. * \param blue Array of 256 blue values.
* \param alpha Array of 256 alpha values. * \param alpha Array of 256 alpha values.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_palette(cucul_dither_t *d,
unsigned int red[], unsigned int green[],
unsigned int blue[], unsigned int alpha[])
int cucul_set_dither_palette(cucul_dither_t *d,
unsigned int red[], unsigned int green[],
unsigned int blue[], unsigned int alpha[])
{ {
int i, has_alpha = 0; int i, has_alpha = 0;


if(d->bpp != 8) if(d->bpp != 8)
return;
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}


for(i = 0; i < 256; i++) for(i = 0; i < 256; i++)
{ {
if(red[i] >= 0 && red[i] < 0x1000 &&
green[i] >= 0 && green[i] < 0x1000 &&
blue[i] >= 0 && blue[i] < 0x1000 &&
alpha[i] >= 0 && alpha[i] < 0x1000)
if((red[i] | green[i] | blue[i] | alpha[i]) >= 0x1000)
{ {
d->red[i] = red[i];
d->green[i] = green[i];
d->blue[i] = blue[i];
if(alpha[i])
{
d->alpha[i] = alpha[i];
has_alpha = 1;
}
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}
}

for(i = 0; i < 256; i++)
{
d->red[i] = red[i];
d->green[i] = green[i];
d->blue[i] = blue[i];
if(alpha[i])
{
d->alpha[i] = alpha[i];
has_alpha = 1;
} }
} }


d->has_alpha = has_alpha; d->has_alpha = has_alpha;

return 0;
} }


/** \brief Set the brightness of a dither object. /** \brief Set the brightness of a dither object.
* *
* Set the brightness of dither. * Set the brightness of dither.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Brightness value was out of range.
*
* \param d Dither object. * \param d Dither object.
* \param brightness brightness value. * \param brightness brightness value.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_brightness(cucul_dither_t *d, float brightness)
int cucul_set_dither_brightness(cucul_dither_t *d, float brightness)
{ {
/* FIXME */ /* FIXME */
return 0;
} }


/** \brief Set the gamma of a dither object. /** \brief Set the gamma of a dither object.
* *
* Set the gamma of dither. * Set the gamma of dither.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Gamma value was out of range.
*
* \param d Dither object. * \param d Dither object.
* \param gamma Gamma value. * \param gamma Gamma value.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_gamma(cucul_dither_t *d, float gamma)
int cucul_set_dither_gamma(cucul_dither_t *d, float gamma)
{ {
/* FIXME: we don't need 4096 calls to gammapow(), we can just compute
/* FIXME: we don't need 4096 calls to gammapow(), we could just compute
* 128 of them and do linear interpolation for the rest. This will * 128 of them and do linear interpolation for the rest. This will
* probably speed up things a lot. */ * probably speed up things a lot. */
int i; int i;


if(gamma <= 0.0) if(gamma <= 0.0)
return;
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}


d->gamma = gamma; d->gamma = gamma;


for(i = 0; i < 4096; i++) for(i = 0; i < 4096; i++)
d->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma); d->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma);

return 0;
} }


/** \brief Invert colors of dither /** \brief Invert colors of dither
* *
* Invert colors of dither
* Invert colors of dither.
*
* This function never fails.
* *
* \param d Dither object. * \param d Dither object.
* \param value 0 for normal behaviour, 1 for invert * \param value 0 for normal behaviour, 1 for invert
* \return This function always returns 0.
*/ */
void cucul_set_dither_invert(cucul_dither_t *d, int value)
int cucul_set_dither_invert(cucul_dither_t *d, int value)
{ {
d->invert = value ? 1 : 0; d->invert = value ? 1 : 0;

return 0;
} }


/** \brief Set the contrast of a dither object. /** \brief Set the contrast of a dither object.
* *
* Set the contrast of dither. * Set the contrast of dither.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Contrast value was out of range.
*
* \param d Dither object. * \param d Dither object.
* \param contrast contrast value. * \param contrast contrast value.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_contrast(cucul_dither_t *d, float contrast)
int cucul_set_dither_contrast(cucul_dither_t *d, float contrast)
{ {
/* FIXME */ /* FIXME */
return 0;
} }


/** \brief Set dither antialiasing /** \brief Set dither antialiasing
@@ -427,19 +488,32 @@ void cucul_set_dither_contrast(cucul_dither_t *d, float contrast)
* *
* \li \c "none": no antialiasing. * \li \c "none": no antialiasing.
* *
* \li \c "prefilter": simple prefilter antialiasing. This is the default
* value.
* \li \c "prefilter" or \c "default": simple prefilter antialiasing. This
* is the default value.
*
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Invalid antialiasing mode.
* *
* \param d Dither object. * \param d Dither object.
* \param str A string describing the antialiasing method that will be used * \param str A string describing the antialiasing method that will be used
* for the dithering. * for the dithering.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_antialias(cucul_dither_t *d, char const *str)
int cucul_set_dither_antialias(cucul_dither_t *d, char const *str)
{ {
if(!strcasecmp(str, "none")) if(!strcasecmp(str, "none"))
d->antialias = 0; d->antialias = 0;
else /* "prefilter" is the default */
else if(!strcasecmp(str, "prefilter") || !strcasecmp(str, "default"))
d->antialias = 1; d->antialias = 1;
else
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}

return 0;
} }


/** \brief Get available antialiasing methods /** \brief Get available antialiasing methods
@@ -450,6 +524,8 @@ void cucul_set_dither_antialias(cucul_dither_t *d, char const *str)
* cucul_set_dither_antialias(), and a string containing the natural * cucul_set_dither_antialias(), and a string containing the natural
* language description for that antialiasing method. * language description for that antialiasing method.
* *
* This function never fails.
*
* \param d Dither object. * \param d Dither object.
* \return An array of strings. * \return An array of strings.
*/ */
@@ -485,14 +561,18 @@ char const * const *
* \li \c "full8": use the 8 ANSI colours for both the characters and the * \li \c "full8": use the 8 ANSI colours for both the characters and the
* background. * background.
* *
* \li \c "full16": use the 16 ANSI colours for both the characters and the
* background. This is the default value.
* \li \c "full16" or \c "default": use the 16 ANSI colours for both the
* characters and the background. This is the default value.
*
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Invalid colour set.
* *
* \param d Dither object. * \param d Dither object.
* \param str A string describing the colour set that will be used * \param str A string describing the colour set that will be used
* for the dithering. * for the dithering.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_color(cucul_dither_t *d, char const *str)
int cucul_set_dither_color(cucul_dither_t *d, char const *str)
{ {
if(!strcasecmp(str, "mono")) if(!strcasecmp(str, "mono"))
d->color_mode = COLOR_MODE_MONO; d->color_mode = COLOR_MODE_MONO;
@@ -506,8 +586,17 @@ void cucul_set_dither_color(cucul_dither_t *d, char const *str)
d->color_mode = COLOR_MODE_FULLGRAY; d->color_mode = COLOR_MODE_FULLGRAY;
else if(!strcasecmp(str, "full8")) else if(!strcasecmp(str, "full8"))
d->color_mode = COLOR_MODE_FULL8; d->color_mode = COLOR_MODE_FULL8;
else /* "full16" is the default */
else if(!strcasecmp(str, "full16") || !strcasecmp(str, "default"))
d->color_mode = COLOR_MODE_FULL16; d->color_mode = COLOR_MODE_FULL16;
else
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}

return 0;
} }


/** \brief Get available colour modes /** \brief Get available colour modes
@@ -518,6 +607,8 @@ void cucul_set_dither_color(cucul_dither_t *d, char const *str)
* cucul_set_dither_color(), and a string containing the natural * cucul_set_dither_color(), and a string containing the natural
* language description for that colour mode. * language description for that colour mode.
* *
* This function never fails.
*
* \param d Dither object. * \param d Dither object.
* \return An array of strings. * \return An array of strings.
*/ */
@@ -544,7 +635,8 @@ char const * const *
* Tell the renderer which characters should be used to render the * Tell the renderer which characters should be used to render the
* dither. Valid values for \c str are: * dither. Valid values for \c str are:
* *
* \li \c "ascii": use only ASCII characters. This is the default value.
* \li \c "ascii" or "default": use only ASCII characters. This is the
* default value.
* *
* \li \c "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592 * \li \c "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592
* MEDIUM SHADE" and "U+2593 DARK SHADE". These characters are also * MEDIUM SHADE" and "U+2593 DARK SHADE". These characters are also
@@ -553,11 +645,15 @@ char const * const *
* \li \c "blocks": use Unicode quarter-cell block combinations. These * \li \c "blocks": use Unicode quarter-cell block combinations. These
* characters are only found in the Unicode set. * characters are only found in the Unicode set.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Invalid character set.
*
* \param d Dither object. * \param d Dither object.
* \param str A string describing the characters that need to be used * \param str A string describing the characters that need to be used
* for the dithering. * for the dithering.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_charset(cucul_dither_t *d, char const *str)
int cucul_set_dither_charset(cucul_dither_t *d, char const *str)
{ {
if(!strcasecmp(str, "shades")) if(!strcasecmp(str, "shades"))
{ {
@@ -569,11 +665,20 @@ void cucul_set_dither_charset(cucul_dither_t *d, char const *str)
d->glyphs = blocks_glyphs; d->glyphs = blocks_glyphs;
d->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs); d->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs);
} }
else /* "ascii" is the default */
else if(!strcasecmp(str, "ascii") || !strcasecmp(str, "default"))
{ {
d->glyphs = ascii_glyphs; d->glyphs = ascii_glyphs;
d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs); d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
} }
else
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}

return 0;
} }


/** \brief Get available dither character sets /** \brief Get available dither character sets
@@ -584,6 +689,8 @@ void cucul_set_dither_charset(cucul_dither_t *d, char const *str)
* cucul_set_dither_charset(), and a string containing the natural * cucul_set_dither_charset(), and a string containing the natural
* language description for that character set. * language description for that character set.
* *
* This function never fails.
*
* \param d Dither object. * \param d Dither object.
* \return An array of strings. * \return An array of strings.
*/ */
@@ -618,11 +725,15 @@ char const * const * cucul_get_dither_charset_list(cucul_dither_t const *d)
* *
* \li \c "fstein": use Floyd-Steinberg dithering. This is the default value. * \li \c "fstein": use Floyd-Steinberg dithering. This is the default value.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Unknown dithering mode.
*
* \param d Dither object. * \param d Dither object.
* \param str A string describing the method that needs to be used * \param str A string describing the method that needs to be used
* for the dithering. * for the dithering.
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_dither_mode(cucul_dither_t *d, char const *str)
int cucul_set_dither_mode(cucul_dither_t *d, char const *str)
{ {
if(!strcasecmp(str, "none")) if(!strcasecmp(str, "none"))
{ {
@@ -654,12 +765,21 @@ void cucul_set_dither_mode(cucul_dither_t *d, char const *str)
d->get_dither = get_random_dither; d->get_dither = get_random_dither;
d->increment_dither = increment_random_dither; d->increment_dither = increment_random_dither;
} }
else /* "fstein" is the default */
else if(!strcasecmp(str, "fstein") || !strcasecmp(str, "default"))
{ {
d->init_dither = init_fstein_dither; d->init_dither = init_fstein_dither;
d->get_dither = get_fstein_dither; d->get_dither = get_fstein_dither;
d->increment_dither = increment_fstein_dither; d->increment_dither = increment_fstein_dither;
} }
else
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}

return 0;
} }


/** \brief Get dithering methods /** \brief Get dithering methods
@@ -670,6 +790,8 @@ void cucul_set_dither_mode(cucul_dither_t *d, char const *str)
* cucul_set_dither_dithering(), and a string containing the natural * cucul_set_dither_dithering(), and a string containing the natural
* language description for that dithering method. * language description for that dithering method.
* *
* This function never fails.
*
* \param d Dither object. * \param d Dither object.
* \return An array of strings. * \return An array of strings.
*/ */
@@ -694,6 +816,8 @@ char const * const * cucul_get_dither_mode_list(cucul_dither_t const *d)
* Dither a bitmap at the given coordinates. The dither can be of any size * Dither a bitmap at the given coordinates. The dither can be of any size
* and will be stretched to the text area. * and will be stretched to the text area.
* *
* This function never fails.
*
* \param cv A handle to the libcucul canvas. * \param cv A handle to the libcucul canvas.
* \param x X coordinate of the upper-left corner of the drawing area. * \param x X coordinate of the upper-left corner of the drawing area.
* \param y Y coordinate of the upper-left corner of the drawing area. * \param y Y coordinate of the upper-left corner of the drawing area.
@@ -701,9 +825,10 @@ char const * const * cucul_get_dither_mode_list(cucul_dither_t const *d)
* \param h Height of the drawing area. * \param h Height of the drawing area.
* \param d Dither object to be drawn. * \param d Dither object to be drawn.
* \param pixels Bitmap's pixels. * \param pixels Bitmap's pixels.
* \return This function always returns 0.
*/ */
void cucul_dither_bitmap(cucul_canvas_t *cv, int x, int y, int w, int h,
cucul_dither_t const *d, void *pixels)
int cucul_dither_bitmap(cucul_canvas_t *cv, int x, int y, int w, int h,
cucul_dither_t const *d, void *pixels)
{ {
int *floyd_steinberg, *fs_r, *fs_g, *fs_b; int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
int fs_length; int fs_length;
@@ -711,7 +836,7 @@ void cucul_dither_bitmap(cucul_canvas_t *cv, int x, int y, int w, int h,
unsigned int dchmax; unsigned int dchmax;


if(!d || !pixels) if(!d || !pixels)
return;
return 0;


x1 = x; x2 = x + w - 1; x1 = x; x2 = x + w - 1;
y1 = y; y2 = y + h - 1; y1 = y; y2 = y + h - 1;
@@ -940,20 +1065,27 @@ void cucul_dither_bitmap(cucul_canvas_t *cv, int x, int y, int w, int h,
} }


free(floyd_steinberg); free(floyd_steinberg);

return 0;
} }


/** \brief Free the memory associated with a dither. /** \brief Free the memory associated with a dither.
* *
* Free the memory allocated by cucul_create_dither(). * Free the memory allocated by cucul_create_dither().
* *
* This function never fails.
*
* \param d Dither object. * \param d Dither object.
* \return This function always returns 0.
*/ */
void cucul_free_dither(cucul_dither_t *d)
int cucul_free_dither(cucul_dither_t *d)
{ {
if(!d) if(!d)
return;
return 0;


free(d); free(d);

return 0;
} }


/* /*


+ 21
- 0
cucul/export.c View File

@@ -20,6 +20,9 @@
#include "common.h" #include "common.h"


#if !defined(__KERNEL__) #if !defined(__KERNEL__)
# if defined(HAVE_ERRNO_H)
# include <errno.h>
# endif
# include <stdlib.h> # include <stdlib.h>
# include <stdio.h> # include <stdio.h>
# include <string.h> # include <string.h>
@@ -63,14 +66,27 @@ static void export_tga(cucul_canvas_t *, cucul_buffer_t *);
* *
* \li \c "tga": export a TGA image. * \li \c "tga": export a TGA image.
* *
* If an error occurs, NULL is returned and \b errno is set accordingly:
* - \c EINVAL Invalid format requested.
* - \c ENOMEM Not enough memory to allocate output buffer.
*
* \param cv A libcucul canvas * \param cv A libcucul canvas
* \param format A string describing the requested output format. * \param format A string describing the requested output format.
* \return A libcucul buffer, or NULL in case of error.
*/ */
cucul_buffer_t * cucul_export_canvas(cucul_canvas_t *cv, char const *format) cucul_buffer_t * cucul_export_canvas(cucul_canvas_t *cv, char const *format)
{ {
cucul_buffer_t *ex; cucul_buffer_t *ex;


ex = malloc(sizeof(cucul_buffer_t)); ex = malloc(sizeof(cucul_buffer_t));
if(!ex)
{
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL;
}

ex->size = 0; ex->size = 0;
ex->data = NULL; ex->data = NULL;
ex->user_data = 0; ex->user_data = 0;
@@ -95,6 +111,9 @@ cucul_buffer_t * cucul_export_canvas(cucul_canvas_t *cv, char const *format)
if(ex->size == 0) if(ex->size == 0)
{ {
free(ex); free(ex);
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL; return NULL;
} }


@@ -108,6 +127,8 @@ cucul_buffer_t * cucul_export_canvas(cucul_canvas_t *cv, char const *format)
* the export format, to be used with cucul_export_canvas(), and a string * the export format, to be used with cucul_export_canvas(), and a string
* containing the natural language description for that export format. * containing the natural language description for that export format.
* *
* This function never fails.
*
* \return An array of strings. * \return An array of strings.
*/ */
char const * const * cucul_get_export_list(void) char const * const * cucul_get_export_list(void)


+ 72
- 4
cucul/font.c View File

@@ -27,6 +27,9 @@
# elif defined(HAVE_NETINET_IN_H) # elif defined(HAVE_NETINET_IN_H)
# include <netinet/in.h> # include <netinet/in.h>
# endif # endif
# if defined(HAVE_ERRNO_H)
# include <errno.h>
# endif
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
@@ -108,6 +111,11 @@ DECLARE_UNPACKGLYPH(1)
* are loaded as a font. This memory are must not be freed by the calling * are loaded as a font. This memory are must not be freed by the calling
* program until the font handle has been freed with cucul_free_font(). * program until the font handle has been freed with cucul_free_font().
* *
* If an error occurs, NULL is returned and \b errno is set accordingly:
* - \c ENOENT Requested built-in font does not exist.
* - \c EINVAL Invalid font data in memory area.
* - \c ENOMEM Not enough memory to allocate font structure.
*
* \param data The memory area containing the font or its name. * \param data The memory area containing the font or its name.
* \param size The size of the memory area, or 0 if the font name is given. * \param size The size of the memory area, or 0 if the font name is given.
* \return A font handle or NULL in case of error. * \return A font handle or NULL in case of error.
@@ -126,13 +134,29 @@ cucul_font_t *cucul_load_font(void const *data, unsigned int size)
return cucul_load_font(monobold12_data, monobold12_size); return cucul_load_font(monobold12_data, monobold12_size);
#endif #endif


#if defined(HAVE_ERRNO_H)
errno = ENOENT;
#endif
return NULL; return NULL;
} }


if(size < sizeof(struct font_header)) if(size < sizeof(struct font_header))
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL; return NULL;
}


f = malloc(sizeof(cucul_font_t)); f = malloc(sizeof(cucul_font_t));
if(!f)
{
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL;
}

f->private = (void *)(uintptr_t)data; f->private = (void *)(uintptr_t)data;


memcpy(&f->header, f->private + 8, sizeof(struct font_header)); memcpy(&f->header, f->private + 8, sizeof(struct font_header));
@@ -152,10 +176,22 @@ cucul_font_t *cucul_load_font(void const *data, unsigned int size)
|| (f->header.flags & 1) == 0) || (f->header.flags & 1) == 0)
{ {
free(f); free(f);
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL; return NULL;
} }


f->block_list = malloc(f->header.blocks * sizeof(struct block_info)); f->block_list = malloc(f->header.blocks * sizeof(struct block_info));
if(!f->block_list)
{
free(f);
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL;
}

memcpy(f->block_list, memcpy(f->block_list,
f->private + 8 + sizeof(struct font_header), f->private + 8 + sizeof(struct font_header),
f->header.blocks * sizeof(struct block_info)); f->header.blocks * sizeof(struct block_info));
@@ -171,11 +207,24 @@ cucul_font_t *cucul_load_font(void const *data, unsigned int size)
{ {
free(f->block_list); free(f->block_list);
free(f); free(f);
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL; return NULL;
} }
} }


f->glyph_list = malloc(f->header.glyphs * sizeof(struct glyph_info)); f->glyph_list = malloc(f->header.glyphs * sizeof(struct glyph_info));
if(!f->glyph_list)
{
free(f->block_list);
free(f);
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL;
}

memcpy(f->glyph_list, memcpy(f->glyph_list,
f->private + 8 + sizeof(struct font_header) f->private + 8 + sizeof(struct font_header)
+ f->header.blocks * sizeof(struct block_info), + f->header.blocks * sizeof(struct block_info),
@@ -194,6 +243,9 @@ cucul_font_t *cucul_load_font(void const *data, unsigned int size)
free(f->glyph_list); free(f->glyph_list);
free(f->block_list); free(f->block_list);
free(f); free(f);
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL; return NULL;
} }
} }
@@ -208,6 +260,8 @@ cucul_font_t *cucul_load_font(void const *data, unsigned int size)
* Return a list of available builtin fonts. The list is a NULL-terminated * Return a list of available builtin fonts. The list is a NULL-terminated
* array of strings. * array of strings.
* *
* This function never fails.
*
* \return An array of strings. * \return An array of strings.
*/ */
char const * const * cucul_get_font_list(void) char const * const * cucul_get_font_list(void)
@@ -226,6 +280,8 @@ char const * const * cucul_get_font_list(void)
* *
* This function returns the maximum value for the current font's glyphs * This function returns the maximum value for the current font's glyphs
* *
* This function never fails.
*
* \param f The font, as returned by cucul_load_font() * \param f The font, as returned by cucul_load_font()
* \return The maximum glyph width. * \return The maximum glyph width.
*/ */
@@ -238,6 +294,8 @@ unsigned int cucul_get_font_width(cucul_font_t *f)
* *
* This function returns the maximum value for the current font's glyphs * This function returns the maximum value for the current font's glyphs
* *
* This function never fails.
*
* \param f The font, as returned by cucul_load_font() * \param f The font, as returned by cucul_load_font()
* \return The maximum glyph height. * \return The maximum glyph height.
*/ */
@@ -253,13 +311,18 @@ unsigned int cucul_get_font_height(cucul_font_t *f)
* this function has returned, the memory area that was given to * this function has returned, the memory area that was given to
* cucul_load_font() can be freed. * cucul_load_font() can be freed.
* *
* This function never fails.
*
* \param f The font, as returned by cucul_load_font() * \param f The font, as returned by cucul_load_font()
* \return This function always returns 0.
*/ */
void cucul_free_font(cucul_font_t *f)
int cucul_free_font(cucul_font_t *f)
{ {
free(f->glyph_list); free(f->glyph_list);
free(f->block_list); free(f->block_list);
free(f); free(f);

return 0;
} }


/** \brief Render the canvas onto an image buffer. /** \brief Render the canvas onto an image buffer.
@@ -275,16 +338,19 @@ void cucul_free_font(cucul_font_t *f)
* Glyphs that do not fit in the image buffer are currently not rendered at * Glyphs that do not fit in the image buffer are currently not rendered at
* all. They may be cropped instead in future versions. * all. They may be cropped instead in future versions.
* *
* This function never fails.
*
* \param cv The canvas to render * \param cv The canvas to render
* \param f The font, as returned by cucul_load_font() * \param f The font, as returned by cucul_load_font()
* \param buf The image buffer * \param buf The image buffer
* \param width The width (in pixels) of the image buffer * \param width The width (in pixels) of the image buffer
* \param height The height (in pixels) of the image buffer * \param height The height (in pixels) of the image buffer
* \param pitch The pitch (in bytes) of an image buffer line. * \param pitch The pitch (in bytes) of an image buffer line.
* \return This function always returns 0.
*/ */
void cucul_render_canvas(cucul_canvas_t *cv, cucul_font_t *f,
void *buf, unsigned int width,
unsigned int height, unsigned int pitch)
int cucul_render_canvas(cucul_canvas_t *cv, cucul_font_t *f,
void *buf, unsigned int width,
unsigned int height, unsigned int pitch)
{ {
uint8_t *glyph = NULL; uint8_t *glyph = NULL;
unsigned int x, y, xmax, ymax; unsigned int x, y, xmax, ymax;
@@ -379,6 +445,8 @@ void cucul_render_canvas(cucul_canvas_t *cv, cucul_font_t *f,


if(f->header.bpp != 8) if(f->header.bpp != 8)
free(glyph); free(glyph);

return 0;
} }


/* /*


+ 284
- 249
cucul/import.c View File

@@ -19,6 +19,9 @@
#include "common.h" #include "common.h"


#if !defined(__KERNEL__) #if !defined(__KERNEL__)
# if defined(HAVE_ERRNO_H)
# include <errno.h>
# endif
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
@@ -43,8 +46,8 @@ static void ansi_parse_grcm(cucul_canvas_t *, struct ansi_grcm *,


/** \brief Import a buffer into a canvas /** \brief Import a buffer into a canvas
* *
* This function imports a libcucul buffer (cucul_load_memory()/cucul_load_file())
* into an internal libcucul canvas.
* This function imports a libcucul buffer as returned by cucul_load_memory()
* or cucul_load_file() into an internal libcucul canvas.
* *
* Valid values for \c format are: * Valid values for \c format are:
* *
@@ -54,6 +57,10 @@ static void ansi_parse_grcm(cucul_canvas_t *, struct ansi_grcm *,
* *
* \li \c "caca": import native libcaca files. * \li \c "caca": import native libcaca files.
* *
* If an error occurs, NULL is returned and \b errno is set accordingly:
* - \c ENOMEM Not enough memory to allocate canvas.
* - \c EINVAL Invalid format requested.
*
* \param buffer A \e libcucul buffer containing the data to be loaded * \param buffer A \e libcucul buffer containing the data to be loaded
* into a canvas. * into a canvas.
* \param format A string describing the input format. * \param format A string describing the input format.
@@ -63,9 +70,6 @@ cucul_canvas_t * cucul_import_canvas(cucul_buffer_t *buffer, char const *format)
{ {
char const *buf = (char const*)buffer->data; char const *buf = (char const*)buffer->data;


if(buffer->size == 0 || buffer->data == NULL)
return NULL;

if(!strcasecmp("caca", format)) if(!strcasecmp("caca", format))
return import_caca(buffer->data, buffer->size); return import_caca(buffer->data, buffer->size);
if(!strcasecmp("text", format)) if(!strcasecmp("text", format))
@@ -75,24 +79,26 @@ cucul_canvas_t * cucul_import_canvas(cucul_buffer_t *buffer, char const *format)


/* Autodetection */ /* Autodetection */
if(!strcasecmp("", format)) if(!strcasecmp("", format))
{
unsigned int i=0;
/* if 4 first letters are CACA */
if(buffer->size >= 4 &&
buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
return import_caca(buffer->data, buffer->size);

/* If we find ESC[ argv, we guess it's an ANSI file */
while(i < buffer->size - 1)
{
if((buf[i] == 0x1b) && (buf[i+1] == '['))
return import_ansi(buffer->data, buffer->size);
i++;
}
{
unsigned int i;


/* Otherwise, import it as text */
return import_text(buffer->data, buffer->size);
}
/* If 4 first letters are CACA */
if(buffer->size >= 4 &&
buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
return import_caca(buffer->data, buffer->size);

/* If we find ESC[ argv, we guess it's an ANSI file */
for(i = 0; i < buffer->size - 1; i++)
if((buf[i] == 0x1b) && (buf[i + 1] == '['))
return import_ansi(buffer->data, buffer->size);

/* Otherwise, import it as text */
return import_text(buffer->data, buffer->size);
}

#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL; return NULL;
} }


@@ -103,6 +109,8 @@ cucul_canvas_t * cucul_import_canvas(cucul_buffer_t *buffer, char const *format)
* the import format, to be used with cucul_import_canvas(), and a string * the import format, to be used with cucul_import_canvas(), and a string
* containing the natural language description for that import format. * containing the natural language description for that import format.
* *
* This function never fails.
*
* \return An array of strings. * \return An array of strings.
*/ */
char const * const * cucul_get_import_list(void) char const * const * cucul_get_import_list(void)
@@ -130,13 +138,13 @@ static cucul_canvas_t *import_caca(void const *data, unsigned int size)
unsigned int width, height, n; unsigned int width, height, n;


if(size < 16) if(size < 16)
return NULL;
goto invalid_caca;


if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A') if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
return NULL;
goto invalid_caca;


if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V') if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V')
return NULL;
goto invalid_caca;


width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16) width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
| ((uint32_t)buf[10] << 8) | (uint32_t)buf[11]; | ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
@@ -144,15 +152,20 @@ static cucul_canvas_t *import_caca(void const *data, unsigned int size)
| ((uint32_t)buf[14] << 8) | (uint32_t)buf[15]; | ((uint32_t)buf[14] << 8) | (uint32_t)buf[15];


if(!width || !height) if(!width || !height)
return NULL;
goto invalid_caca;


if(size != 16 + width * height * 8) if(size != 16 + width * height * 8)
return NULL;
goto invalid_caca;


cv = cucul_create_canvas(width, height); cv = cucul_create_canvas(width, height);


if(!cv) if(!cv)
{
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL; return NULL;
}


for(n = height * width; n--; ) for(n = height * width; n--; )
{ {
@@ -167,6 +180,12 @@ static cucul_canvas_t *import_caca(void const *data, unsigned int size)
} }


return cv; return cv;

invalid_caca:
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return NULL;
} }


static cucul_canvas_t *import_text(void const *data, unsigned int size) static cucul_canvas_t *import_text(void const *data, unsigned int size)
@@ -176,37 +195,45 @@ static cucul_canvas_t *import_text(void const *data, unsigned int size)
unsigned int width = 1, height = 1, x = 0, y = 0, i; unsigned int width = 1, height = 1, x = 0, y = 0, i;


cv = cucul_create_canvas(width, height); cv = cucul_create_canvas(width, height);
if(!cv)
{
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL;
}

cucul_set_color(cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_TRANSPARENT); cucul_set_color(cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_TRANSPARENT);


for(i = 0; i < size; i++) for(i = 0; i < size; i++)
{
unsigned char ch = *text++;
{
unsigned char ch = *text++;


if(ch == '\r')
continue;
if(ch == '\r')
continue;


if(ch == '\n')
{
x = 0;
y++;
continue;
}

if(x >= width || y >= height)
{
if(x >= width)
width = x + 1;
if(ch == '\n')
{
x = 0;
y++;
continue;
}


if(y >= height)
height = y + 1;
if(x >= width || y >= height)
{
if(x >= width)
width = x + 1;


cucul_set_canvas_size(cv, width, height);
}
if(y >= height)
height = y + 1;


cucul_putchar(cv, x, y, ch);
x++;
cucul_set_canvas_size(cv, width, height);
} }


cucul_putchar(cv, x, y, ch);
x++;
}

return cv; return cv;
} }


@@ -220,158 +247,166 @@ static cucul_canvas_t *import_ansi(void const *data, unsigned int size)
int x = 0, y = 0, save_x = 0, save_y = 0; int x = 0, y = 0, save_x = 0, save_y = 0;


cv = cucul_create_canvas(width, height); cv = cucul_create_canvas(width, height);
if(!cv)
{
#if defined(HAVE_ERRNO_H)
errno = ENOMEM;
#endif
return NULL;
}

ansi_parse_grcm(cv, &grcm, 1, &dummy); ansi_parse_grcm(cv, &grcm, 1, &dummy);


for(i = 0; i < size; i += skip) for(i = 0; i < size; i += skip)
{
skip = 1;

/* Wrap long lines */
if((unsigned int)x >= width)
{ {
skip = 1;
x = 0;
y++;
}


/* Wrap long lines */
if((unsigned int)x >= width)
{
x = 0;
y++;
}
if(buffer[i] == '\x1a' && size - i >= 8
&& !memcmp(buffer + i + 1, "SAUCE00", 7))
break; /* End before SAUCE data */


if(buffer[i] == '\x1a' && size - i >= 8
&& !memcmp(buffer + i + 1, "SAUCE00", 7))
break; /* End before SAUCE data */
if(buffer[i] == '\r')
continue; /* DOS sucks */


if(buffer[i] == '\r')
continue; /* DOS sucks */
if(buffer[i] == '\n')
{
x = 0;
y++;
continue;
}


if(buffer[i] == '\n')
{
x = 0;
y++;
continue;
}
/* Interpret escape commands, as per Standard ECMA-48 "Control
* Functions for Coded Character Sets", 5.4. Control sequences. */
if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
{
unsigned int argc = 0, argv[101];
unsigned int param, inter, final;

/* Compute offsets to parameter bytes, intermediate bytes and
* to the final byte. Only the final byte is mandatory, there
* can be zero of the others.
* 0 param=2 inter final final+1
* +-----+------------------+---------------------+-----------------+
* | CSI | parameter bytes | intermediate bytes | final byte |
* | | 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e |
* | ^[[ | 0123456789:;<=>? | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |
* +-----+------------------+---------------------+-----------------+
*/
param = 2;

for(inter = param; i + inter < size; inter++)
if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
break;


/* Interpret escape commands, as per Standard ECMA-48 "Control
* Functions for Coded Character Sets", 5.4. Control sequences. */
if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
{
unsigned int argc = 0, argv[101];
unsigned int param, inter, final;

/* Compute offsets to parameter bytes, intermediate bytes and
* to the final byte. Only the final byte is mandatory, there
* can be zero of the others.
* 0 param=2 inter final final+1
* +-----+------------------+---------------------+-----------------+
* | CSI | parameter bytes | intermediate bytes | final byte |
* | | 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e |
* | ^[[ | 0123456789:;<=>? | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |
* +-----+------------------+---------------------+-----------------+
*/
param = 2;

for(inter = param; i + inter < size; inter++)
if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
break;

for(final = inter; i + final < size; final++)
if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
break;

if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
break; /* Invalid Final Byte */

skip += final;

/* Sanity checks */
if(param < inter && buffer[i + param] >= 0x3c)
{
fprintf(stderr, "private sequence \"^[[%.*s\"\n",
final - param + 1, buffer + i + param);
continue; /* Private sequence, skip it entirely */
}

if(final - param > 100)
continue; /* Suspiciously long sequence, skip it */

/* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string
* format */
if(param < inter)
{
argv[0] = 0;
for(j = param; j < inter; j++)
{
if(buffer[i + j] == ';')
argv[++argc] = 0;
else if(buffer[i + j] >= '0' && buffer[i + j] <= '9')
argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
}
argc++;
}

/* Interpret final byte. The code representations are given in
* ECMA-48 5.4: Control sequences, and the code definitions are
* given in ECMA-48 8.3: Definition of control functions. */
switch(buffer[i + final])
{
case 'f': /* CUP - Cursor Position */
case 'H': /* HVP - Character And Line Position */
x = (argc > 1) ? argv[1] - 1 : 0;
y = (argc > 0) ? argv[0] - 1 : 0;
break;
case 'A': /* CUU - Cursor Up */
y -= argc ? argv[0] : 1;
if(y < 0)
y = 0;
break;
case 'B': /* CUD - Cursor Down */
y += argc ? argv[0] : 1;
break;
case 'C': /* CUF - Cursor Right */
x += argc ? argv[0] : 1;
break;
case 'D': /* CUB - Cursor Left */
x -= argc ? argv[0] : 1;
if(x < 0)
x = 0;
break;
case 's': /* Private (save cursor position) */
save_x = x;
save_y = y;
break;
case 'u': /* Private (reload cursor positin) */
x = save_x;
y = save_y;
break;
case 'J': /* ED - Erase In Page */
if(argv[0] == 2)
x = y = 0;
break;
case 'K': /* EL - Erase In Line */
for(j = x; j < width; j++)
_cucul_putchar32(cv, j, y, (uint32_t)' ');
x = width;
break;
case 'm': /* SGR - Select Graphic Rendition */
ansi_parse_grcm(cv, &grcm, argc, argv);
break;
default:
fprintf(stderr, "unknown command %c\n", buffer[i + final]);
break;
}

continue;
}
for(final = inter; i + final < size; final++)
if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
break;

if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
break; /* Invalid Final Byte */

skip += final;

/* Sanity checks */
if(param < inter && buffer[i + param] >= 0x3c)
{
fprintf(stderr, "private sequence \"^[[%.*s\"\n",
final - param + 1, buffer + i + param);
continue; /* Private sequence, skip it entirely */
}


/* We're going to paste a character. First make sure the canvas
* is big enough. */
if((unsigned int)y >= height)
if(final - param > 100)
continue; /* Suspiciously long sequence, skip it */

/* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string
* format */
if(param < inter)
{
argv[0] = 0;
for(j = param; j < inter; j++)
{ {
height = y + 1;
cucul_set_canvas_size(cv, width, height);
if(buffer[i + j] == ';')
argv[++argc] = 0;
else if(buffer[i + j] >= '0' && buffer[i + j] <= '9')
argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
} }
argc++;
}

/* Interpret final byte. The code representations are given in
* ECMA-48 5.4: Control sequences, and the code definitions are
* given in ECMA-48 8.3: Definition of control functions. */
switch(buffer[i + final])
{
case 'f': /* CUP - Cursor Position */
case 'H': /* HVP - Character And Line Position */
x = (argc > 1) ? argv[1] - 1 : 0;
y = (argc > 0) ? argv[0] - 1 : 0;
break;
case 'A': /* CUU - Cursor Up */
y -= argc ? argv[0] : 1;
if(y < 0)
y = 0;
break;
case 'B': /* CUD - Cursor Down */
y += argc ? argv[0] : 1;
break;
case 'C': /* CUF - Cursor Right */
x += argc ? argv[0] : 1;
break;
case 'D': /* CUB - Cursor Left */
x -= argc ? argv[0] : 1;
if(x < 0)
x = 0;
break;
case 's': /* Private (save cursor position) */
save_x = x;
save_y = y;
break;
case 'u': /* Private (reload cursor positin) */
x = save_x;
y = save_y;
break;
case 'J': /* ED - Erase In Page */
if(argv[0] == 2)
x = y = 0;
break;
case 'K': /* EL - Erase In Line */
for(j = x; j < width; j++)
_cucul_putchar32(cv, j, y, (uint32_t)' ');
x = width;
break;
case 'm': /* SGR - Select Graphic Rendition */
ansi_parse_grcm(cv, &grcm, argc, argv);
break;
default:
fprintf(stderr, "unknown command %c\n", buffer[i + final]);
break;
}

continue;
}


/* Now paste our character */
_cucul_putchar32(cv, x, y, _cucul_cp437_to_utf32(buffer[i]));
x++;
/* We're going to paste a character. First make sure the canvas
* is big enough. */
if((unsigned int)y >= height)
{
height = y + 1;
cucul_set_canvas_size(cv, width, height);
} }


/* Now paste our character */
_cucul_putchar32(cv, x, y, _cucul_cp437_to_utf32(buffer[i]));
x++;
}

return cv; return cv;
} }


@@ -381,82 +416,82 @@ static void ansi_parse_grcm(cucul_canvas_t *cv, struct ansi_grcm *g,
unsigned int argc, unsigned int const *argv) unsigned int argc, unsigned int const *argv)
{ {
static uint8_t const ansi2cucul[] = static uint8_t const ansi2cucul[] =
{
CUCUL_COLOR_BLACK, CUCUL_COLOR_RED,
CUCUL_COLOR_GREEN, CUCUL_COLOR_BROWN,
CUCUL_COLOR_BLUE, CUCUL_COLOR_MAGENTA,
CUCUL_COLOR_CYAN, CUCUL_COLOR_LIGHTGRAY
};
{
CUCUL_COLOR_BLACK, CUCUL_COLOR_RED,
CUCUL_COLOR_GREEN, CUCUL_COLOR_BROWN,
CUCUL_COLOR_BLUE, CUCUL_COLOR_MAGENTA,
CUCUL_COLOR_CYAN, CUCUL_COLOR_LIGHTGRAY
};


unsigned int j; unsigned int j;
uint8_t myfg, mybg; uint8_t myfg, mybg;


for(j = 0; j < argc; j++) for(j = 0; j < argc; j++)
{
/* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */
if(argv[j] >= 30 && argv[j] <= 37)
g->fg = ansi2cucul[argv[j] - 30];
else if(argv[j] >= 40 && argv[j] <= 47)
g->bg = ansi2cucul[argv[j] - 40];
else if(argv[j] >= 90 && argv[j] <= 97)
g->fg = ansi2cucul[argv[j] - 90] + 8;
else if(argv[j] >= 100 && argv[j] <= 107)
g->bg = ansi2cucul[argv[j] - 100] + 8;
else switch(argv[j])
{ {
/* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */
if(argv[j] >= 30 && argv[j] <= 37)
g->fg = ansi2cucul[argv[j] - 30];
else if(argv[j] >= 40 && argv[j] <= 47)
g->bg = ansi2cucul[argv[j] - 40];
else if(argv[j] >= 90 && argv[j] <= 97)
g->fg = ansi2cucul[argv[j] - 90] + 8;
else if(argv[j] >= 100 && argv[j] <= 107)
g->bg = ansi2cucul[argv[j] - 100] + 8;
else switch(argv[j])
{
case 0: /* default rendition */
g->fg = CUCUL_COLOR_DEFAULT;
g->bg = CUCUL_COLOR_DEFAULT;
g->bold = g->negative = g->concealed = 0;
break;
case 1: /* bold or increased intensity */
g->bold = 1;
break;
case 4: /* singly underlined */
break;
case 5: /* slowly blinking (less then 150 per minute) */
break;
case 7: /* negative image */
g->negative = 1;
break;
case 8: /* concealed characters */
g->concealed = 1;
break;
case 22: /* normal colour or normal intensity (neither bold nor faint) */
g->bold = 0;
break;
case 28: /* revealed characters */
g->concealed = 0;
break;
case 39: /* default display colour (implementation-defined) */
g->fg = CUCUL_COLOR_DEFAULT;
break;
case 49: /* default background colour (implementation-defined) */
g->bg = CUCUL_COLOR_DEFAULT;
break;
default:
fprintf(stderr, "unknown sgr %i\n", argv[j]);
break;
}
case 0: /* default rendition */
g->fg = CUCUL_COLOR_DEFAULT;
g->bg = CUCUL_COLOR_DEFAULT;
g->bold = g->negative = g->concealed = 0;
break;
case 1: /* bold or increased intensity */
g->bold = 1;
break;
case 4: /* singly underlined */
break;
case 5: /* slowly blinking (less then 150 per minute) */
break;
case 7: /* negative image */
g->negative = 1;
break;
case 8: /* concealed characters */
g->concealed = 1;
break;
case 22: /* normal colour or normal intensity (neither bold nor faint) */
g->bold = 0;
break;
case 28: /* revealed characters */
g->concealed = 0;
break;
case 39: /* default display colour (implementation-defined) */
g->fg = CUCUL_COLOR_DEFAULT;
break;
case 49: /* default background colour (implementation-defined) */
g->bg = CUCUL_COLOR_DEFAULT;
break;
default:
fprintf(stderr, "unknown sgr %i\n", argv[j]);
break;
} }
}


if(g->concealed) if(g->concealed)
{
myfg = mybg = CUCUL_COLOR_TRANSPARENT;
}
{
myfg = mybg = CUCUL_COLOR_TRANSPARENT;
}
else else
{
myfg = g->negative ? g->bg : g->fg;
mybg = g->negative ? g->fg : g->bg;
{
myfg = g->negative ? g->bg : g->fg;
mybg = g->negative ? g->fg : g->bg;


if(g->bold)
{
if(myfg < 8)
myfg += 8;
else if(myfg == CUCUL_COLOR_DEFAULT)
myfg = CUCUL_COLOR_WHITE;
}
if(g->bold)
{
if(myfg < 8)
myfg += 8;
else if(myfg == CUCUL_COLOR_DEFAULT)
myfg = CUCUL_COLOR_WHITE;
} }
}


cucul_set_color(cv, myfg, mybg); cucul_set_color(cv, myfg, mybg);
} }


+ 45
- 6
cucul/sprite.c View File

@@ -22,6 +22,9 @@
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
# if defined(HAVE_ERRNO_H)
# include <errno.h>
# endif
#endif #endif


#include "cucul.h" #include "cucul.h"
@@ -31,6 +34,8 @@
* *
* This function returns the current canvas frame count. * This function returns the current canvas frame count.
* *
* This function never fails.
*
* \param cv A libcucul canvas * \param cv A libcucul canvas
* \return The frame count * \return The frame count
*/ */
@@ -47,18 +52,29 @@ unsigned int cucul_get_canvas_frame_count(cucul_canvas_t *cv)
* *
* If the frame index is outside the canvas' frame range, nothing happens. * If the frame index is outside the canvas' frame range, nothing happens.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Requested frame is out of range.
*
* \param cv A libcucul canvas * \param cv A libcucul canvas
* \param frame The canvas frame to activate * \param frame The canvas frame to activate
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_set_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
int cucul_set_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
{ {
if(frame >= cv->framecount) if(frame >= cv->framecount)
return;
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}


cv->frame = frame; cv->frame = frame;


cv->chars = cv->allchars[cv->frame]; cv->chars = cv->allchars[cv->frame];
cv->attr = cv->allattr[cv->frame]; cv->attr = cv->allattr[cv->frame];

return 0;
} }


/** \brief Add a frame to a canvas. /** \brief Add a frame to a canvas.
@@ -74,10 +90,14 @@ void cucul_set_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
* The active frame does not change, but its index may be renumbered due * The active frame does not change, but its index may be renumbered due
* to the insertion. * to the insertion.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c ENOMEM Not enough memory to allocate new frame.
*
* \param cv A libcucul canvas * \param cv A libcucul canvas
* \param frame The index where to insert the new frame * \param frame The index where to insert the new frame
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_create_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
int cucul_create_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
{ {
unsigned int size = cv->width * cv->height * sizeof(uint32_t); unsigned int size = cv->width * cv->height * sizeof(uint32_t);
unsigned int f; unsigned int f;
@@ -105,6 +125,8 @@ void cucul_create_canvas_frame(cucul_canvas_t *cv, unsigned int frame)


cv->chars = cv->allchars[cv->frame]; cv->chars = cv->allchars[cv->frame];
cv->attr = cv->allattr[cv->frame]; cv->attr = cv->allattr[cv->frame];

return 0;
} }


/** \brief Remove a frame from a canvas. /** \brief Remove a frame from a canvas.
@@ -123,18 +145,33 @@ void cucul_create_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
* Otherwise, the active frame does not change, but its index may be * Otherwise, the active frame does not change, but its index may be
* renumbered due to the deletion. * renumbered due to the deletion.
* *
* If an error occurs, -1 is returned and \b errno is set accordingly:
* - \c EINVAL Requested frame is out of range, or attempt to delete the
* last frame of the canvas.
*
* \param cv A libcucul canvas * \param cv A libcucul canvas
* \param frame The index of the frame to delete * \param frame The index of the frame to delete
* \return 0 in case of success, -1 if an error occurred.
*/ */
void cucul_free_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
int cucul_free_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
{ {
unsigned int f; unsigned int f;


if(frame >= cv->framecount) if(frame >= cv->framecount)
return;
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}


if(cv->framecount == 1) if(cv->framecount == 1)
return;
{
#if defined(HAVE_ERRNO_H)
errno = EINVAL;
#endif
return -1;
}


free(cv->allchars[frame]); free(cv->allchars[frame]);
free(cv->allattr[frame]); free(cv->allattr[frame]);
@@ -156,5 +193,7 @@ void cucul_free_canvas_frame(cucul_canvas_t *cv, unsigned int frame)


cv->chars = cv->allchars[cv->frame]; cv->chars = cv->allchars[cv->frame];
cv->attr = cv->allattr[cv->frame]; cv->attr = cv->allattr[cv->frame];

return 0;
} }



+ 24
- 4
cucul/transform.c View File

@@ -33,9 +33,12 @@ static uint32_t rotatechar(uint32_t ch);
* This function inverts a canvas' colours (black becomes white, red * This function inverts a canvas' colours (black becomes white, red
* becomes cyan, etc.) without changing the characters in it. * becomes cyan, etc.) without changing the characters in it.
* *
* This function never fails.
*
* \param cv The canvas to invert. * \param cv The canvas to invert.
* \return This function always returns 0.
*/ */
void cucul_invert(cucul_canvas_t *cv)
int cucul_invert(cucul_canvas_t *cv)
{ {
uint32_t *attr = cv->attr; uint32_t *attr = cv->attr;
unsigned int i; unsigned int i;
@@ -45,6 +48,8 @@ void cucul_invert(cucul_canvas_t *cv)
*attr = *attr ^ 0x000f000f; *attr = *attr ^ 0x000f000f;
attr++; attr++;
} }

return 0;
} }


/** \brief Flip a canvas horizontally. /** \brief Flip a canvas horizontally.
@@ -52,9 +57,12 @@ void cucul_invert(cucul_canvas_t *cv)
* This function flips a canvas horizontally, choosing characters that * This function flips a canvas horizontally, choosing characters that
* look like the mirrored version wherever possible. * look like the mirrored version wherever possible.
* *
* This function never fails.
*
* \param cv The canvas to flip. * \param cv The canvas to flip.
* \return This function always returns 0.
*/ */
void cucul_flip(cucul_canvas_t *cv)
int cucul_flip(cucul_canvas_t *cv)
{ {
unsigned int y; unsigned int y;


@@ -82,6 +90,8 @@ void cucul_flip(cucul_canvas_t *cv)
if(cleft == cright) if(cleft == cright)
*cleft = flipchar(*cleft); *cleft = flipchar(*cleft);
} }

return 0;
} }


/** \brief Flip a canvas vertically. /** \brief Flip a canvas vertically.
@@ -89,9 +99,12 @@ void cucul_flip(cucul_canvas_t *cv)
* This function flips a canvas vertically, choosing characters that * This function flips a canvas vertically, choosing characters that
* look like the mirrored version wherever possible. * look like the mirrored version wherever possible.
* *
* This function never fails.
*
* \param cv The canvas to flop. * \param cv The canvas to flop.
* \return This function always returns 0.
*/ */
void cucul_flop(cucul_canvas_t *cv)
int cucul_flop(cucul_canvas_t *cv)
{ {
unsigned int x; unsigned int x;


@@ -120,6 +133,8 @@ void cucul_flop(cucul_canvas_t *cv)
if(ctop == cbottom) if(ctop == cbottom)
*ctop = flopchar(*ctop); *ctop = flopchar(*ctop);
} }

return 0;
} }


/** \brief Rotate a canvas. /** \brief Rotate a canvas.
@@ -128,9 +143,12 @@ void cucul_flop(cucul_canvas_t *cv)
* choosing characters that look like the mirrored version wherever * choosing characters that look like the mirrored version wherever
* possible. * possible.
* *
* This function never fails.
*
* \param cv The canvas to rotate. * \param cv The canvas to rotate.
* \return This function always returns 0.
*/ */
void cucul_rotate(cucul_canvas_t *cv)
int cucul_rotate(cucul_canvas_t *cv)
{ {
uint32_t *cbegin = cv->chars; uint32_t *cbegin = cv->chars;
uint32_t *cend = cbegin + cv->width * cv->height - 1; uint32_t *cend = cbegin + cv->width * cv->height - 1;
@@ -153,6 +171,8 @@ void cucul_rotate(cucul_canvas_t *cv)


if(cbegin == cend) if(cbegin == cend)
*cbegin = rotatechar(*cbegin); *cbegin = rotatechar(*cbegin);

return 0;
} }


static uint32_t flipchar(uint32_t ch) static uint32_t flipchar(uint32_t ch)


Loading…
Cancel
Save