* Got rid of static buffers; we now use cucul_free() to free exported
buffers.
* Fixed light background in the ANSI exporter by adding escape sequences for
most terminal emulators.
tags/v0.99.beta14
| @@ -85,8 +85,7 @@ struct driver_private | |||
| char prefix[sizeof(INIT_PREFIX)]; | |||
| char *buffer; | |||
| int size; | |||
| struct cucul_buffer *ex; | |||
| int client_count; | |||
| struct client *clients; | |||
| @@ -169,8 +168,7 @@ static int network_init_graphics(caca_t *kk) | |||
| return -1; | |||
| } | |||
| kk->drv.p->buffer = NULL; | |||
| kk->drv.p->size = 0; | |||
| kk->drv.p->ex = NULL; | |||
| /* Ignore SIGPIPE */ | |||
| kk->drv.p->sigpipe_handler = signal(SIGPIPE, SIG_IGN); | |||
| @@ -191,6 +189,9 @@ static int network_end_graphics(caca_t *kk) | |||
| kk->drv.p->clients[i].fd = -1; | |||
| } | |||
| if(kk->drv.p->ex) | |||
| cucul_free(kk->drv.p->ex); | |||
| /* Restore SIGPIPE handler */ | |||
| signal(SIGPIPE, kk->drv.p->sigpipe_handler); | |||
| @@ -219,10 +220,17 @@ static void network_display(caca_t *kk) | |||
| { | |||
| int i; | |||
| /* Free the previous export buffer, if any */ | |||
| if(kk->drv.p->ex) | |||
| { | |||
| cucul_free(kk->drv.p->ex); | |||
| kk->drv.p->ex = NULL; | |||
| } | |||
| /* Get ANSI representation of the image and skip the end-of buffer | |||
| * linefeed ("\r\n\0", 3 bytes) */ | |||
| kk->drv.p->buffer = cucul_get_ansi(kk->qq, 0, &kk->drv.p->size); | |||
| kk->drv.p->size -= 3; | |||
| kk->drv.p->ex = cucul_export(kk->qq, CUCUL_FORMAT_ANSI); | |||
| kk->drv.p->ex->size -= 3; | |||
| for(i = 0; i < kk->drv.p->client_count; i++) | |||
| { | |||
| @@ -370,7 +378,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
| } | |||
| /* No error, there's just nothing to send yet */ | |||
| if(!kk->drv.p->buffer) | |||
| if(!kk->drv.p->ex) | |||
| return 0; | |||
| /* If we have backlog, send the backlog */ | |||
| @@ -395,7 +403,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
| { | |||
| c->start += ret; | |||
| if(c->stop - c->start + strlen(ANSI_PREFIX) + kk->drv.p->size | |||
| if(c->stop - c->start + strlen(ANSI_PREFIX) + kk->drv.p->ex->size | |||
| > OUTBUFFER) | |||
| { | |||
| /* Overflow! Empty buffer and start again */ | |||
| @@ -406,7 +414,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
| } | |||
| /* Need to move? */ | |||
| if(c->stop + strlen(ANSI_PREFIX) + kk->drv.p->size > OUTBUFFER) | |||
| if(c->stop + strlen(ANSI_PREFIX) + kk->drv.p->ex->size > OUTBUFFER) | |||
| { | |||
| memmove(c->outbuf, c->outbuf + c->start, c->stop - c->start); | |||
| c->stop -= c->start; | |||
| @@ -415,8 +423,8 @@ static int send_data(caca_t *kk, struct client *c) | |||
| memcpy(c->outbuf + c->stop, ANSI_PREFIX, strlen(ANSI_PREFIX)); | |||
| c->stop += strlen(ANSI_PREFIX); | |||
| memcpy(c->outbuf + c->stop, kk->drv.p->buffer, kk->drv.p->size); | |||
| c->stop += kk->drv.p->size; | |||
| memcpy(c->outbuf + c->stop, kk->drv.p->ex->buffer, kk->drv.p->ex->size); | |||
| c->stop += kk->drv.p->ex->size; | |||
| return 0; | |||
| } | |||
| @@ -436,7 +444,7 @@ static int send_data(caca_t *kk, struct client *c) | |||
| if(ret < (ssize_t)strlen(ANSI_PREFIX)) | |||
| { | |||
| if(strlen(ANSI_PREFIX) + kk->drv.p->size > OUTBUFFER) | |||
| if(strlen(ANSI_PREFIX) + kk->drv.p->ex->size > OUTBUFFER) | |||
| { | |||
| /* Overflow! Empty buffer and start again */ | |||
| memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET)); | |||
| @@ -447,14 +455,14 @@ static int send_data(caca_t *kk, struct client *c) | |||
| memcpy(c->outbuf, ANSI_PREFIX, strlen(ANSI_PREFIX) - ret); | |||
| c->stop = strlen(ANSI_PREFIX) - ret; | |||
| memcpy(c->outbuf + c->stop, kk->drv.p->buffer, kk->drv.p->size); | |||
| c->stop += kk->drv.p->size; | |||
| memcpy(c->outbuf + c->stop, kk->drv.p->ex->buffer, kk->drv.p->ex->size); | |||
| c->stop += kk->drv.p->ex->size; | |||
| return 0; | |||
| } | |||
| /* Send actual data */ | |||
| ret = nonblock_write(c->fd, kk->drv.p->buffer, kk->drv.p->size); | |||
| ret = nonblock_write(c->fd, kk->drv.p->ex->buffer, kk->drv.p->ex->size); | |||
| if(ret == -1) | |||
| { | |||
| if(errno == EAGAIN) | |||
| @@ -463,9 +471,9 @@ static int send_data(caca_t *kk, struct client *c) | |||
| return -1; | |||
| } | |||
| if(ret < kk->drv.p->size) | |||
| if(ret < (int)kk->drv.p->ex->size) | |||
| { | |||
| if(kk->drv.p->size > OUTBUFFER) | |||
| if(kk->drv.p->ex->size > OUTBUFFER) | |||
| { | |||
| /* Overflow! Empty buffer and start again */ | |||
| memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET)); | |||
| @@ -474,8 +482,8 @@ static int send_data(caca_t *kk, struct client *c) | |||
| return 0; | |||
| } | |||
| memcpy(c->outbuf, kk->drv.p->buffer, kk->drv.p->size - ret); | |||
| c->stop = kk->drv.p->size - ret; | |||
| memcpy(c->outbuf, kk->drv.p->ex->buffer, kk->drv.p->ex->size - ret); | |||
| c->stop = kk->drv.p->ex->size - ret; | |||
| return 0; | |||
| } | |||
| @@ -74,11 +74,6 @@ cucul_t * cucul_init(void) | |||
| return NULL; | |||
| } | |||
| qq->ansi_buffer = NULL; | |||
| qq->irc_buffer = NULL; | |||
| qq->html3_buffer = NULL; | |||
| qq->html_buffer = NULL; | |||
| return qq; | |||
| } | |||
| @@ -277,19 +272,44 @@ void cucul_end(cucul_t *qq) | |||
| free(qq->chars); | |||
| free(qq->attr); | |||
| if(qq->ansi_buffer) | |||
| free(qq->ansi_buffer); | |||
| if(qq->irc_buffer) | |||
| free(qq->irc_buffer); | |||
| if(qq->html3_buffer) | |||
| free(qq->html3_buffer); | |||
| if(qq->html_buffer) | |||
| free(qq->html_buffer); | |||
| if(qq->ps_buffer) | |||
| free(qq->ps_buffer); | |||
| free(qq); | |||
| } | |||
| struct cucul_buffer * cucul_export(cucul_t *qq, enum cucul_format format) | |||
| { | |||
| struct cucul_buffer *ex; | |||
| free(qq); | |||
| ex = malloc(sizeof(struct cucul_buffer)); | |||
| switch(format) | |||
| { | |||
| case CUCUL_FORMAT_ANSI: | |||
| _cucul_get_ansi(qq, ex); | |||
| break; | |||
| case CUCUL_FORMAT_HTML: | |||
| _cucul_get_html(qq, ex); | |||
| break; | |||
| case CUCUL_FORMAT_HTML3: | |||
| _cucul_get_html3(qq, ex); | |||
| break; | |||
| case CUCUL_FORMAT_IRC: | |||
| _cucul_get_irc(qq, ex); | |||
| break; | |||
| case CUCUL_FORMAT_PS: | |||
| _cucul_get_ps(qq, ex); | |||
| break; | |||
| default: | |||
| free(ex); | |||
| return NULL; | |||
| } | |||
| return ex; | |||
| } | |||
| void cucul_free(struct cucul_buffer *ex) | |||
| { | |||
| free(ex->buffer); | |||
| free(ex); | |||
| } | |||
| /* | |||
| @@ -28,7 +28,7 @@ extern "C" | |||
| /** \brief Colour definitions. | |||
| * | |||
| * Colours that can be used with caca_set_color(). | |||
| * Colours that can be used with cucul_set_color(). | |||
| */ | |||
| enum cucul_color | |||
| { | |||
| @@ -50,6 +50,19 @@ enum cucul_color | |||
| CUCUL_COLOR_WHITE = 15 /**< The colour index for white. */ | |||
| }; | |||
| /** \brief Export formats | |||
| * | |||
| * Export formats understood by libcucul. | |||
| */ | |||
| enum cucul_format | |||
| { | |||
| CUCUL_FORMAT_ANSI = 0, /**< Export to ANSI format. */ | |||
| CUCUL_FORMAT_HTML = 1, /**< Export to HTML format. */ | |||
| CUCUL_FORMAT_HTML3 = 2, /**< Export to old HTMLv3 format. */ | |||
| CUCUL_FORMAT_IRC = 3, /**< Export to text with mIRC colours. */ | |||
| CUCUL_FORMAT_PS = 4, /**< Export to PostScript. */ | |||
| }; | |||
| /** \brief Internal features. | |||
| * | |||
| * Internal libcaca features such as the rendering method or the dithering | |||
| @@ -200,15 +213,18 @@ void cucul_free_bitmap(cucul_t *, struct cucul_bitmap *); | |||
| /** \defgroup exporter Exporters to various formats | |||
| * | |||
| * These functions exports current image to various text formats | |||
| * Returned buffer will be freed() each you'll call the exporter function. | |||
| * These functions export the current canvas to various text formats. It | |||
| * is necessary to call cucul_free() to dispose of the data. | |||
| * | |||
| * @{ */ | |||
| char* cucul_get_html(cucul_t *, int *size); | |||
| char* cucul_get_html3(cucul_t *, int *size); | |||
| char* cucul_get_irc(cucul_t *, int *size); | |||
| char* cucul_get_ansi(cucul_t *, int trailing, int *size); | |||
| char* cucul_get_ps(cucul_t *qq, int *size); | |||
| struct cucul_buffer | |||
| { | |||
| unsigned int size; | |||
| char *buffer; | |||
| }; | |||
| struct cucul_buffer * cucul_export(cucul_t *, enum cucul_format); | |||
| void cucul_free(struct cucul_buffer *); | |||
| /* @} */ | |||
| @@ -47,13 +47,6 @@ struct cucul_context | |||
| enum cucul_feature background, antialiasing, dithering; | |||
| unsigned int refcount; | |||
| /* Exporters facilities */ | |||
| char *ansi_buffer; | |||
| char *irc_buffer; | |||
| char *html3_buffer; | |||
| char *html_buffer; | |||
| char *ps_buffer; | |||
| }; | |||
| /* Initialisation functions */ | |||
| @@ -10,7 +10,7 @@ | |||
| */ | |||
| /** \file export.c | |||
| * \version \$Id: export.c 361 2006-03-09 13:24:06Z jylam $ | |||
| * \version \$Id$ | |||
| * \author Sam Hocevar <sam@zoy.org> | |||
| * \author Jean-Yves Lamoureux <jylam@lnxscene.org> | |||
| * \brief Export function | |||
| @@ -39,28 +39,24 @@ | |||
| * able to cut/paste the result to a function like printf | |||
| * \return buffer containing generated ANSI codes as a big string | |||
| */ | |||
| char * cucul_get_ansi(cucul_t *qq, int trailing, int *size) | |||
| void _cucul_get_ansi(cucul_t *qq, struct cucul_buffer *ex) | |||
| { | |||
| static int const palette[] = | |||
| { | |||
| 30, 34, 32, 36, 31, 35, 33, 37, /* Both lines (light and dark) are the same, */ | |||
| 30, 34, 32, 36, 31, 35, 33, 37, /* light colors handling is done later */ | |||
| 0, 4, 2, 6, 1, 5, 3, 7, | |||
| 8, 12, 10, 14, 9, 13, 11, 15 | |||
| }; | |||
| char *cur; | |||
| unsigned int x, y; | |||
| /* 20 bytes assumed for max length per pixel. | |||
| /* 23 bytes assumed for max length per pixel ('\e[5;1;3x;4y;9x;10ym' plus | |||
| * 4 max bytes for a UTF-8 character). | |||
| * Add height*9 to that (zeroes color at the end and jump to next line) */ | |||
| if(qq->ansi_buffer) | |||
| free(qq->ansi_buffer); | |||
| qq->ansi_buffer = malloc(((qq->height*9) + (qq->width * qq->height * 20)) * sizeof(char)); | |||
| if(qq->ansi_buffer == NULL) | |||
| return NULL; | |||
| ex->size = (qq->height * 9) + (qq->width * qq->height * 23); | |||
| ex->buffer = malloc(ex->size); | |||
| cur = qq->ansi_buffer; | |||
| // *cur++ = ''; | |||
| cur = ex->buffer; | |||
| for(y = 0; y < qq->height; y++) | |||
| { | |||
| @@ -73,34 +69,39 @@ char * cucul_get_ansi(cucul_t *qq, int trailing, int *size) | |||
| for(x = 0; x < qq->width; x++) | |||
| { | |||
| uint8_t fg = palette[lineattr[x] & 0x0f]; | |||
| uint8_t bg = (palette[lineattr[x] >> 4])+10; | |||
| uint8_t bg = palette[lineattr[x] >> 4]; | |||
| uint32_t c = linechar[x]; | |||
| if(!trailing) | |||
| cur += sprintf(cur, "\033["); | |||
| else | |||
| cur += sprintf(cur, "\\033["); | |||
| if(fg != prevfg || bg != prevbg) | |||
| { | |||
| cur += sprintf(cur, "\033[0;"); | |||
| if(fg < 8) | |||
| if(bg < 8) | |||
| cur += sprintf(cur, "3%d;4%dm", fg, bg); | |||
| else | |||
| cur += sprintf(cur, "5;3%d;4%d;10%dm", | |||
| fg, bg - 8, bg - 8); | |||
| else | |||
| if(bg < 8) | |||
| cur += sprintf(cur, "1;3%d;4%d;9%dm", | |||
| fg - 8, bg, fg - 8); | |||
| else | |||
| cur += sprintf(cur, "5;1;3%d;4%d;9%d;10%dm", | |||
| fg - 8, bg - 8, fg - 8, bg - 8); | |||
| } | |||
| if(fg > 7) | |||
| cur += sprintf(cur, "1;%d;%dm",fg,bg); | |||
| else | |||
| cur += sprintf(cur, "0;%d;%dm",fg,bg); | |||
| *cur++ = c & 0x7f; | |||
| if((c == '%') && trailing) | |||
| *cur++ = c & 0x7f; | |||
| prevfg = fg; | |||
| prevbg = bg; | |||
| } | |||
| if(!trailing) | |||
| cur += sprintf(cur, "\033[0m\r\n"); | |||
| else | |||
| cur += sprintf(cur, "\\033[0m\\n\n"); | |||
| cur += sprintf(cur, "\033[0m\r\n"); | |||
| } | |||
| /* Crop to really used size */ | |||
| *size = (strlen(qq->ansi_buffer) + 1)* sizeof(char); | |||
| qq->ansi_buffer = realloc(qq->ansi_buffer, *size); | |||
| return qq->ansi_buffer; | |||
| ex->size = strlen(ex->buffer) + 1; | |||
| ex->buffer = realloc(ex->buffer, ex->size); | |||
| } | |||
| @@ -10,7 +10,7 @@ | |||
| */ | |||
| /** \file export.c | |||
| * \version \$Id: export.c 361 2006-03-09 13:24:06Z jylam $ | |||
| * \version \$Id$ | |||
| * \author Sam Hocevar <sam@zoy.org> | |||
| * \author Jean-Yves Lamoureux <jylam@lnxscene.org> | |||
| * \brief Export function | |||
| @@ -38,7 +38,7 @@ | |||
| * This function generates and returns the HTML representation of | |||
| * the current image. | |||
| */ | |||
| char* cucul_get_html(cucul_t *qq, int *size) | |||
| void _cucul_get_html(cucul_t *qq, struct cucul_buffer *ex) | |||
| { | |||
| static int const palette[] = | |||
| { | |||
| @@ -51,15 +51,10 @@ char* cucul_get_html(cucul_t *qq, int *size) | |||
| /* 13000 -> css palette | |||
| * 40 -> max size used for a pixel (plus 10, never know)*/ | |||
| /* FIXME: Check this value */ | |||
| if(qq->html_buffer) | |||
| free(qq->html_buffer); | |||
| ex->size = 13000 + (qq->width * qq->height * 40); | |||
| ex->buffer = malloc(ex->size); | |||
| qq->html_buffer = malloc((13000 + ((qq->width*qq->height) * 40)) * sizeof(char)); | |||
| if(qq->html_buffer == NULL) | |||
| return NULL; | |||
| cur = qq->html_buffer; | |||
| cur = ex->buffer; | |||
| /* HTML header */ | |||
| cur += sprintf(cur, "<html>\n<head>\n<title>Generated by libcaca %s</title>\n", VERSION); | |||
| @@ -104,10 +99,8 @@ char* cucul_get_html(cucul_t *qq, int *size) | |||
| cur += sprintf(cur, "</div></body></html>\n"); | |||
| /* Crop to really used size */ | |||
| *size = (strlen(qq->html_buffer) + 1) * sizeof(char); | |||
| qq->html_buffer = realloc(qq->html_buffer, *size); | |||
| return qq->html_buffer; | |||
| ex->size = strlen(ex->buffer) + 1; | |||
| ex->buffer = realloc(ex->buffer, ex->size); | |||
| } | |||
| @@ -119,7 +112,7 @@ char* cucul_get_html(cucul_t *qq, int *size) | |||
| * Won't work under gecko (mozilla rendering engine) unless you set | |||
| * a correct header. | |||
| */ | |||
| char* cucul_get_html3(cucul_t *qq, int *size) | |||
| void _cucul_get_html3(cucul_t *qq, struct cucul_buffer *ex) | |||
| { | |||
| static int const palette[] = | |||
| { | |||
| @@ -128,20 +121,16 @@ char* cucul_get_html3(cucul_t *qq, int *size) | |||
| 0x444444, 0x4444ff, 0x44ff44, 0x44ffff, | |||
| 0xff4444, 0xff44ff, 0xffff44, 0xffffff, | |||
| }; | |||
| char *cur; | |||
| unsigned int x, y, len; | |||
| /* 13000 -> css palette | |||
| * 40 -> max size used for a pixel (plus 10, never know) */ | |||
| ex->size = 13000 + (qq->width * qq->height * 40); | |||
| ex->buffer = malloc(ex->size); | |||
| if(qq->html3_buffer) | |||
| free(qq->html3_buffer); | |||
| qq->html3_buffer = malloc((13000 + ((qq->width*qq->height)*40))*sizeof(char)); | |||
| if(qq->html3_buffer == NULL) | |||
| return NULL; | |||
| cur = qq->html3_buffer; | |||
| cur = ex->buffer; | |||
| /* Table */ | |||
| cur += sprintf(cur, "<table cols='%d' cellpadding='0' cellspacing='0'>\n", | |||
| @@ -189,10 +178,8 @@ char* cucul_get_html3(cucul_t *qq, int *size) | |||
| cur += sprintf(cur, "</table>\n"); | |||
| /* Crop to really used size */ | |||
| *size = (strlen(qq->html3_buffer) + 1) * sizeof(char); | |||
| qq->html3_buffer = realloc(qq->html3_buffer, *size); | |||
| return qq->html3_buffer; | |||
| ex->size = strlen(ex->buffer) + 1; | |||
| ex->buffer = realloc(ex->buffer, ex->size); | |||
| } | |||
| @@ -10,7 +10,7 @@ | |||
| */ | |||
| /** \file export.c | |||
| * \version \$Id: export.c 361 2006-03-09 13:24:06Z jylam $ | |||
| * \version \$Id$ | |||
| * \author Sam Hocevar <sam@zoy.org> | |||
| * \author Jean-Yves Lamoureux <jylam@lnxscene.org> | |||
| * \brief Export function | |||
| @@ -36,7 +36,7 @@ | |||
| * This function generates and returns an IRC representation of | |||
| * the current image. | |||
| */ | |||
| char* cucul_get_irc(cucul_t *qq, int *size) | |||
| void _cucul_get_irc(cucul_t *qq, struct cucul_buffer *ex) | |||
| { | |||
| static int const palette[] = | |||
| { | |||
| @@ -55,14 +55,10 @@ char* cucul_get_irc(cucul_t *qq, int *size) | |||
| * In real life, the average bytes per pixel value will be around 5. | |||
| */ | |||
| if(qq->irc_buffer) | |||
| free(qq->irc_buffer); | |||
| ex->size = 2 + (qq->width * qq->height * 11); | |||
| ex->buffer = malloc(ex->size); | |||
| qq->irc_buffer = malloc((2 + (qq->width * qq->height * 11)) * sizeof(char)); | |||
| if(qq->irc_buffer == NULL) | |||
| return NULL; | |||
| cur = qq->irc_buffer; | |||
| cur = ex->buffer; | |||
| *cur++ = '\x0f'; | |||
| @@ -114,8 +110,6 @@ char* cucul_get_irc(cucul_t *qq, int *size) | |||
| *cur++ = '\x0f'; | |||
| /* Crop to really used size */ | |||
| *size = (strlen(qq->irc_buffer) + 1) * sizeof(char); | |||
| qq->irc_buffer = realloc(qq->irc_buffer, *size); | |||
| return qq->irc_buffer; | |||
| ex->size = strlen(ex->buffer) + 1; | |||
| ex->buffer = realloc(ex->buffer, ex->size); | |||
| } | |||
| @@ -59,7 +59,7 @@ static char const *ps_header = | |||
| * This function generates and returns a Postscript representation of | |||
| * the current image. | |||
| */ | |||
| char* cucul_get_ps(cucul_t *qq, int *size) | |||
| void _cucul_get_ps(cucul_t *qq, struct cucul_buffer *ex) | |||
| { | |||
| char *cur; | |||
| int x, y; | |||
| @@ -87,17 +87,15 @@ char* cucul_get_ps(cucul_t *qq, int *size) | |||
| }; | |||
| if(qq->ps_buffer) | |||
| free(qq->ps_buffer); | |||
| /* 200 is arbitrary but should be ok */ | |||
| qq->ps_buffer = malloc((strlen(ps_header) + (qq->height*qq->width)*200) * sizeof(char)); | |||
| cur = qq->ps_buffer; | |||
| ex->size = strlen(ps_header) + (qq->width * qq->height * 200); | |||
| ex->buffer = malloc(ex->size); | |||
| cur = ex->buffer; | |||
| /* Header */ | |||
| cur += sprintf(cur, "%s", ps_header); | |||
| /* Background, drawn using csquare macro defined in header */ | |||
| for(y=(int)(qq->height-1);y>=0; y--) { | |||
| uint8_t *lineattr = qq->attr + y * qq->width; | |||
| @@ -139,13 +137,7 @@ char* cucul_get_ps(cucul_t *qq, int *size) | |||
| cur += sprintf(cur, "showpage"); | |||
| /* Crop to really used size */ | |||
| *size = (strlen(qq->ps_buffer) + 1) * sizeof(char); | |||
| qq->ps_buffer = realloc(qq->ps_buffer, *size); | |||
| return qq->ps_buffer; | |||
| ex->size = strlen(ex->buffer) + 1; | |||
| ex->buffer = realloc(ex->buffer, ex->size); | |||
| } | |||