libcaca  0.99.beta19
About: libcaca is a graphics library that outputs text instead of pixels, so that it can work on older video cards or text terminals (something like an advanced AAlib library).
  Fossies Dox: libcaca-0.99.beta19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

string.c
Go to the documentation of this file.
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://www.wtfpl.net/ for more details.
11  */
12 
13 /*
14  * This file contains various canvas handling functions such as character
15  * and string drawing.
16  */
17 
18 #include "config.h"
19 
20 #if !defined(__KERNEL__)
21 # include <stdio.h> /* BUFSIZ */
22 # include <string.h>
23 # include <stdlib.h>
24 # include <stdarg.h>
25 # if defined(HAVE_UNISTD_H)
26 # include <unistd.h>
27 # endif
28 # if defined(HAVE_SIGNAL_H)
29 # include <signal.h>
30 # endif
31 # if defined(HAVE_SYS_IOCTL_H)
32 # include <sys/ioctl.h>
33 # endif
34 #endif
35 
36 #include "caca.h"
37 #include "caca_internals.h"
38 
39 #if defined _WIN32 && defined __GNUC__ && __GNUC__ >= 3
40 int vsnprintf_s(char *s, size_t n, size_t c,
41  const char *fmt, va_list ap) CACA_WEAK;
42 int vsnprintf(char *s, size_t n, const char *fmt, va_list ap) CACA_WEAK;
43 #endif
44 
58 int caca_gotoxy(caca_canvas_t *cv, int x, int y)
59 {
60  cv->frames[cv->frame].x = x;
61  cv->frames[cv->frame].y = y;
62 
63  return 0;
64 }
65 
76 {
77  return cv->frames[cv->frame].x;
78 }
79 
90 {
91  return cv->frames[cv->frame].y;
92 }
93 
120 int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch)
121 {
122  uint32_t *curchar, *curattr, attr;
123  int fullwidth, xmin, xmax, ret;
124 
125  if(ch == CACA_MAGIC_FULLWIDTH)
126  return 1;
127 
128  fullwidth = caca_utf32_is_fullwidth(ch);
129  ret = fullwidth ? 2 : 1;
130 
131  if(x >= (int)cv->width || y < 0 || y >= (int)cv->height)
132  return ret;
133 
134  if(x == -1 && fullwidth)
135  {
136  x = 0;
137  ch = ' ';
138  fullwidth = 0;
139  }
140  else if(x < 0)
141  return ret;
142 
143  curchar = cv->chars + x + y * cv->width;
144  curattr = cv->attrs + x + y * cv->width;
145  attr = cv->curattr;
146 
147  xmin = xmax = x;
148 
149  /* When overwriting the right part of a fullwidth character,
150  * replace its left part with a space. */
151  if(x && curchar[0] == CACA_MAGIC_FULLWIDTH)
152  {
153  curchar[-1] = ' ';
154  xmin--;
155  }
156 
157  if(fullwidth)
158  {
159  if(x + 1 == (int)cv->width)
160  ch = ' ';
161  else
162  {
163  xmax++;
164 
165  /* When overwriting the left part of a fullwidth character,
166  * replace its right part with a space. */
167  if(x + 2 < (int)cv->width && curchar[2] == CACA_MAGIC_FULLWIDTH)
168  {
169  curchar[2] = ' ';
170  xmax++;
171  }
172 
173  curchar[1] = CACA_MAGIC_FULLWIDTH;
174  curattr[1] = attr;
175  }
176  }
177  else
178  {
179  /* When overwriting the left part of a fullwidth character,
180  * replace its right part with a space. */
181  if(x + 1 != (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH)
182  {
183  curchar[1] = ' ';
184  xmax++;
185  }
186  }
187 
188  /* Only add a dirty rectangle if we are pasting a different character
189  * or attribute at that place. This does not account for inconsistencies
190  * in the canvas, ie. if CACA_MAGIC_FULLWIDTH lies at illegal places,
191  * but it's the caller's responsibility not to corrupt the contents. */
192  if(!cv->dirty_disabled
193  && (curchar[0] != ch || curattr[0] != attr))
194  caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1);
195 
196  curchar[0] = ch;
197  curattr[0] = attr;
198 
199  return ret;
200 }
201 
224 uint32_t caca_get_char(caca_canvas_t const *cv, int x, int y)
225 {
226  if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
227  return ' ';
228 
229  return cv->chars[x + y * cv->width];
230 }
231 
254 int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s)
255 {
256  size_t rd;
257  int len = 0;
258 
259  if (y < 0 || y >= (int)cv->height || x >= (int)cv->width)
260  {
261  while (*s)
262  {
263  len += caca_utf32_is_fullwidth(caca_utf8_to_utf32(s, &rd)) ? 2 : 1;
264  s += rd ? rd : 1;
265  }
266  return len;
267  }
268 
269  while (*s)
270  {
271  uint32_t ch = caca_utf8_to_utf32(s, &rd);
272 
273  if (x + len >= -1 && x + len < (int)cv->width)
274  caca_put_char(cv, x + len, y, ch);
275 
276  len += caca_utf32_is_fullwidth(ch) ? 2 : 1;
277  s += rd ? rd : 1;
278  }
279 
280  return len;
281 }
282 
304 int caca_printf(caca_canvas_t *cv, int x, int y, char const *format, ...)
305 {
306  va_list args;
307  int ret;
308  va_start(args, format);
309  ret = caca_vprintf(cv, x, y, format, args);
310  va_end(args);
311  return ret;
312 }
313 
335 int caca_vprintf(caca_canvas_t *cv, int x, int y, char const *format,
336  va_list args)
337 {
338  char tmp[BUFSIZ];
339  char *buf = tmp;
340  int bufsize = BUFSIZ, ret;
341 
342  if(cv->width - x + 1 > BUFSIZ)
343  {
344  bufsize = cv->width - x + 1;
345  buf = malloc(bufsize);
346  }
347 
348 #if defined(HAVE_VSNPRINTF_S)
349  vsnprintf_s(buf, bufsize, _TRUNCATE, format, args);
350 #elif defined(HAVE_VSNPRINTF)
351  vsnprintf(buf, bufsize, format, args);
352 #else
353  vsprintf(buf, format, args);
354 #endif
355  buf[bufsize - 1] = '\0';
356 
357  ret = caca_put_str(cv, x, y, buf);
358 
359  if(buf != tmp)
360  free(buf);
361 
362  return ret;
363 }
364 
375 {
376  uint32_t attr = cv->curattr;
377  int n;
378 
379  for(n = cv->width * cv->height; n--; )
380  {
381  cv->chars[n] = (uint32_t)' ';
382  cv->attrs[n] = attr;
383  }
384 
385  if(!cv->dirty_disabled)
386  caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
387 
388  return 0;
389 }
390 
404 {
405  cv->frames[cv->frame].handlex = x;
406  cv->frames[cv->frame].handley = y;
407 
408  return 0;
409 }
410 
421 {
422  return cv->frames[cv->frame].handlex;
423 }
424 
435 {
436  return cv->frames[cv->frame].handley;
437 }
438 
455 int caca_blit(caca_canvas_t *dst, int x, int y,
456  caca_canvas_t const *src, caca_canvas_t const *mask)
457 {
458  int i, j, starti, startj, endi, endj, stride, bleed_left, bleed_right;
459 
460  if(mask && (src->width != mask->width || src->height != mask->height))
461  {
462  seterrno(EINVAL);
463  return -1;
464  }
465 
466  x -= src->frames[src->frame].handlex;
467  y -= src->frames[src->frame].handley;
468 
469  starti = x < 0 ? -x : 0;
470  startj = y < 0 ? -y : 0;
471  endi = (x + src->width >= dst->width) ? dst->width - x : src->width;
472  endj = (y + src->height >= dst->height) ? dst->height - y : src->height;
473  stride = endi - starti;
474 
475  if(starti > src->width || startj > src->height
476  || starti >= endi || startj >= endj)
477  return 0;
478 
479  bleed_left = bleed_right = 0;
480 
481  for(j = startj; j < endj; j++)
482  {
483  int dstix = (j + y) * dst->width + starti + x;
484  int srcix = j * src->width + starti;
485 
486  /* FIXME: we are ignoring the mask here */
487  if((starti + x) && dst->chars[dstix] == CACA_MAGIC_FULLWIDTH)
488  {
489  dst->chars[dstix - 1] = ' ';
490  bleed_left = 1;
491  }
492 
493  if(endi + x < dst->width
494  && dst->chars[dstix + stride] == CACA_MAGIC_FULLWIDTH)
495  {
496  dst->chars[dstix + stride] = ' ';
497  bleed_right = 1;
498  }
499 
500  if(mask)
501  {
502  for(i = 0; i < stride; i++)
503  {
504  if(mask->chars[srcix + i] == (uint32_t)' ')
505  continue;
506 
507  if(dst->chars[dstix + i] != src->chars[srcix + i] ||
508  dst->attrs[dstix + i] != src->attrs[srcix + i])
509  {
510  dst->chars[dstix + i] = src->chars[srcix + i];
511  dst->attrs[dstix + i] = src->attrs[srcix + i];
512  if(!dst->dirty_disabled)
513  caca_add_dirty_rect(dst, x + starti + i, y + j, 1, 1);
514  }
515  }
516  }
517  else
518  {
519  if(memcmp(dst->chars + dstix, src->chars + srcix, stride * 4) ||
520  memcmp(dst->attrs + dstix, src->attrs + srcix, stride * 4))
521  {
522  /* FIXME be more precise ? */
523  memcpy(dst->chars + dstix, src->chars + srcix, stride * 4);
524  memcpy(dst->attrs + dstix, src->attrs + srcix, stride * 4);
525  if(!dst->dirty_disabled)
526  caca_add_dirty_rect(dst, x + starti, y + j, stride, 1);
527  }
528  }
529 
530  /* Fix split fullwidth chars */
531  if(src->chars[srcix] == CACA_MAGIC_FULLWIDTH)
532  dst->chars[dstix] = ' ';
533 
534  if(endi < src->width && src->chars[endi] == CACA_MAGIC_FULLWIDTH)
535  dst->chars[dstix + stride - 1] = ' ';
536  }
537 
538 
539  return 0;
540 }
541 
561 int caca_set_canvas_boundaries(caca_canvas_t *cv, int x, int y, int w, int h)
562 {
563  caca_canvas_t *new;
564  int f, saved_f, framecount;
565 
566  if(cv->refcount)
567  {
568  seterrno(EBUSY);
569  return -1;
570  }
571 
572  if(w < 0 || h < 0)
573  {
574  seterrno(EINVAL);
575  return -1;
576  }
577 
578  new = caca_create_canvas(w, h);
579 
580  framecount = caca_get_frame_count(cv);
581  saved_f = cv->frame;
582 
583  for(f = 0; f < framecount; f++)
584  {
585  if(f)
586  caca_create_frame(new, framecount);
587 
588  caca_set_frame(cv, f);
589  caca_set_frame(new, f);
590  caca_blit(new, -x, -y, cv, NULL);
591  free(cv->frames[f].chars);
592  free(cv->frames[f].attrs);
593  }
594  free(cv->frames);
595 
596  cv->frames = new->frames;
597  free(new);
598 
599  caca_set_frame(cv, saved_f);
601 
602  /* FIXME: this may be optimised somewhat */
603  if(!cv->dirty_disabled)
604  caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
605 
606  return 0;
607 }
608 
609 /*
610  * Functions for the mingw32 runtime
611  */
612 
613 #if defined _WIN32 && defined __GNUC__ && __GNUC__ >= 3
614 int vsnprintf_s(char *s, size_t n, size_t c, const char *fmt, va_list ap)
615 {
616  return vsnprintf(s, n, fmt, ap);
617 }
618 
619 int vsnprintf(char *s, size_t n, const char *fmt, va_list ap)
620 {
621  return 0;
622 }
623 #endif
624 
625 /*
626  * XXX: The following functions are aliases.
627  */
628 
634 int cucul_put_char(cucul_canvas_t *, int, int, uint32_t)
636 uint32_t cucul_get_char(cucul_canvas_t const *, int, int)
638 int cucul_put_str(cucul_canvas_t *, int, int, char const *)
640 int cucul_printf(cucul_canvas_t *, int, int, char const *, ...)
649 int cucul_blit(cucul_canvas_t *, int, int, cucul_canvas_t const *,
651 int cucul_set_canvas_boundaries(cucul_canvas_t *, int, int, int, int)
653 
cucul_printf
#define cucul_printf
Definition: caca.h:813
caca_wherey
int caca_wherey(caca_canvas_t const *cv)
Get Y cursor position.
Definition: string.c:89
caca_get_canvas_handle_y
int caca_get_canvas_handle_y(caca_canvas_t const *cv)
Get Y handle position.
Definition: string.c:434
cucul_set_canvas_boundaries
#define cucul_set_canvas_boundaries
Definition: caca.h:819
caca_wherex
int caca_wherex(caca_canvas_t const *cv)
Get X cursor position.
Definition: string.c:75
CACA_ALIAS
#define CACA_ALIAS(x)
Definition: caca.h:689
caca_blit
int caca_blit(caca_canvas_t *dst, int x, int y, caca_canvas_t const *src, caca_canvas_t const *mask)
Blit a canvas onto another one.
Definition: string.c:455
CACA_WEAK
#define CACA_WEAK
Definition: caca.h:695
caca_canvas::frame
int frame
Definition: caca_internals.h:53
caca_frame::handley
int handley
Definition: caca_internals.h:40
y
static int y
Definition: cacadraw.c:27
caca_create_frame
int caca_create_frame(caca_canvas_t *, int)
Add a frame to a canvas.
Definition: frame.c:145
caca_create_canvas
caca_canvas_t * caca_create_canvas(int, int)
Initialise a libcaca canvas.
Definition: canvas.c:54
cucul_gotoxy
#define cucul_gotoxy
Definition: caca.h:807
_caca_load_frame_info
void _caca_load_frame_info(caca_canvas_t *)
Definition: frame.c:257
cucul_get_cursor_y
#define cucul_get_cursor_y
Definition: caca.h:809
caca_canvas::curattr
uint32_t curattr
Definition: caca_internals.h:74
caca_canvas::frames
struct caca_frame * frames
Definition: caca_internals.h:54
cucul_get_canvas_handle_x
#define cucul_get_canvas_handle_x
Definition: caca.h:816
caca_get_cursor_y
#define caca_get_cursor_y
Definition: caca.h:796
caca_canvas::attrs
uint32_t * attrs
Definition: caca_internals.h:73
cucul_get_char
#define cucul_get_char
Definition: caca.h:811
caca_canvas::chars
uint32_t * chars
Definition: caca_internals.h:72
caca_put_str
int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s)
Print a string.
Definition: string.c:254
seterrno
#define seterrno(x)
Definition: caca_stubs.h:27
caca_add_dirty_rect
int caca_add_dirty_rect(caca_canvas_t *, int, int, int, int)
Add an area to the canvas's dirty rectangle list.
Definition: dirty.c:164
cucul_canvas_t
#define cucul_canvas_t
Definition: caca.h:763
caca_frame::x
int x
Definition: caca_internals.h:39
cucul_get_cursor_x
#define cucul_get_cursor_x
Definition: caca.h:808
cv
caca_canvas_t * cv
Definition: cacaview.c:45
caca_printf
int caca_printf(caca_canvas_t *cv, int x, int y, char const *format,...)
Print a formated string.
Definition: string.c:304
caca_gotoxy
int caca_gotoxy(caca_canvas_t *cv, int x, int y)
Set cursor position.
Definition: string.c:58
caca_get_canvas_handle_x
int caca_get_canvas_handle_x(caca_canvas_t const *cv)
Get X handle position.
Definition: string.c:420
caca_canvas::dirty_disabled
int dirty_disabled
Definition: caca_internals.h:63
cucul_set_canvas_handle
#define cucul_set_canvas_handle
Definition: caca.h:815
caca_put_char
int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch)
Print an ASCII or Unicode character.
Definition: string.c:120
caca_frame::chars
uint32_t * chars
Definition: caca_internals.h:35
caca_internals.h
caca_set_canvas_handle
int caca_set_canvas_handle(caca_canvas_t *cv, int x, int y)
Set cursor handle.
Definition: string.c:403
caca_vprintf
int caca_vprintf(caca_canvas_t *cv, int x, int y, char const *format, va_list args)
Print a formated string (va_list version).
Definition: string.c:335
caca_utf8_to_utf32
uint32_t caca_utf8_to_utf32(char const *, size_t *)
Convert a UTF-8 character to UTF-32.
Definition: charset.c:112
cucul_get_canvas_handle_y
#define cucul_get_canvas_handle_y
Definition: caca.h:817
caca_get_cursor_x
#define caca_get_cursor_x
Definition: caca.h:795
caca_frame::y
int y
Definition: caca_internals.h:39
caca_frame::handlex
int handlex
Definition: caca_internals.h:40
caca_canvas::width
int width
Definition: caca_internals.h:71
cucul_blit
#define cucul_blit
Definition: caca.h:818
caca_canvas::refcount
int refcount
Definition: caca_internals.h:57
caca.h
The libcaca public header.
caca_utf32_is_fullwidth
int caca_utf32_is_fullwidth(uint32_t)
Tell whether a UTF-32 character is fullwidth.
Definition: charset.c:388
caca_set_canvas_boundaries
int caca_set_canvas_boundaries(caca_canvas_t *cv, int x, int y, int w, int h)
Set a canvas' new boundaries.
Definition: string.c:561
config.h
caca_get_char
uint32_t caca_get_char(caca_canvas_t const *cv, int x, int y)
Get the Unicode character at the given coordinates.
Definition: string.c:224
caca_clear_canvas
int caca_clear_canvas(caca_canvas_t *cv)
Clear the canvas.
Definition: string.c:374
caca_frame::attrs
uint32_t * attrs
Definition: caca_internals.h:36
CACA_MAGIC_FULLWIDTH
#define CACA_MAGIC_FULLWIDTH
Definition: caca.h:250
caca_set_frame
int caca_set_frame(caca_canvas_t *, int)
Activate a given canvas frame.
Definition: frame.c:57
caca_canvas::height
int height
Definition: caca_internals.h:71
cucul_put_str
#define cucul_put_str
Definition: caca.h:812
cucul_clear_canvas
#define cucul_clear_canvas
Definition: caca.h:814
cucul_put_char
#define cucul_put_char
Definition: caca.h:810
caca_canvas
Definition: caca_internals.h:47
x
static int x
Definition: cacadraw.c:27
caca_get_frame_count
int caca_get_frame_count(caca_canvas_t const *)
Get the number of frames in a canvas.
Definition: frame.c:37