- Timestamp:
- Apr 27, 2006, 4:15:23 PM (15 years ago)
- Location:
- libcaca/trunk/cucul
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
libcaca/trunk/cucul/cucul.h
r896 r920 113 113 * 114 114 * @{ */ 115 voidcucul_invert(cucul_canvas_t *);116 voidcucul_flip(cucul_canvas_t *);117 voidcucul_flop(cucul_canvas_t *);118 voidcucul_rotate(cucul_canvas_t *);115 int cucul_invert(cucul_canvas_t *); 116 int cucul_flip(cucul_canvas_t *); 117 int cucul_flop(cucul_canvas_t *); 118 int cucul_rotate(cucul_canvas_t *); 119 119 /* @} */ 120 120 … … 151 151 * @{ */ 152 152 unsigned int cucul_get_canvas_frame_count(cucul_canvas_t *); 153 voidcucul_set_canvas_frame(cucul_canvas_t *, unsigned int);154 voidcucul_create_canvas_frame(cucul_canvas_t *, unsigned int);155 voidcucul_free_canvas_frame(cucul_canvas_t *, unsigned int);153 int cucul_set_canvas_frame(cucul_canvas_t *, unsigned int); 154 int cucul_create_canvas_frame(cucul_canvas_t *, unsigned int); 155 int cucul_free_canvas_frame(cucul_canvas_t *, unsigned int); 156 156 /* @} */ 157 157 … … 166 166 unsigned int, unsigned int, 167 167 unsigned int, unsigned int); 168 voidcucul_set_dither_palette(cucul_dither_t *,169 170 171 voidcucul_set_dither_brightness(cucul_dither_t *, float);172 voidcucul_set_dither_gamma(cucul_dither_t *, float);173 voidcucul_set_dither_contrast(cucul_dither_t *, float);174 voidcucul_set_dither_invert(cucul_dither_t *, int);175 voidcucul_set_dither_antialias(cucul_dither_t *, char const *);168 int cucul_set_dither_palette(cucul_dither_t *, 169 unsigned int r[], unsigned int g[], 170 unsigned int b[], unsigned int a[]); 171 int cucul_set_dither_brightness(cucul_dither_t *, float); 172 int cucul_set_dither_gamma(cucul_dither_t *, float); 173 int cucul_set_dither_contrast(cucul_dither_t *, float); 174 int cucul_set_dither_invert(cucul_dither_t *, int); 175 int cucul_set_dither_antialias(cucul_dither_t *, char const *); 176 176 char const * const * cucul_get_dither_antialias_list(cucul_dither_t const *); 177 voidcucul_set_dither_color(cucul_dither_t *, char const *);177 int cucul_set_dither_color(cucul_dither_t *, char const *); 178 178 char const * const * cucul_get_dither_color_list(cucul_dither_t const *); 179 voidcucul_set_dither_charset(cucul_dither_t *, char const *);179 int cucul_set_dither_charset(cucul_dither_t *, char const *); 180 180 char const * const * cucul_get_dither_charset_list(cucul_dither_t const *); 181 voidcucul_set_dither_mode(cucul_dither_t *, char const *);181 int cucul_set_dither_mode(cucul_dither_t *, char const *); 182 182 char const * const * cucul_get_dither_mode_list(cucul_dither_t const *); 183 voidcucul_dither_bitmap(cucul_canvas_t *, int, int, int, int,183 int cucul_dither_bitmap(cucul_canvas_t *, int, int, int, int, 184 184 cucul_dither_t const *, void *); 185 voidcucul_free_dither(cucul_dither_t *);185 int cucul_free_dither(cucul_dither_t *); 186 186 /* @} */ 187 187 … … 196 196 unsigned int cucul_get_font_width(cucul_font_t *); 197 197 unsigned int cucul_get_font_height(cucul_font_t *); 198 voidcucul_render_canvas(cucul_canvas_t *, cucul_font_t *, void *,198 int cucul_render_canvas(cucul_canvas_t *, cucul_font_t *, void *, 199 199 unsigned int, unsigned int, unsigned int); 200 voidcucul_free_font(cucul_font_t *);200 int cucul_free_font(cucul_font_t *); 201 201 /* @} */ 202 202 -
libcaca/trunk/cucul/dither.c
r859 r920 27 27 # include <limits.h> 28 28 # include <string.h> 29 # if defined(HAVE_ERRNO_H) 30 # include <errno.h> 31 # endif 29 32 #endif 30 33 … … 237 240 * pixel, a zero alpha mask causes the alpha values to be ignored. 238 241 * 242 * If an error occurs, NULL is returned and \b errno is set accordingly: 243 * - \c EINVAL Requested width, height, pitch or bits per pixel value was 244 * invalid. 245 * - \c ENOMEM Not enough memory to allocate dither structure. 246 * 239 247 * \param bpp Bitmap depth in bits per pixel. 240 248 * \param w Bitmap width in pixels. … … 245 253 * \param bmask Bitmask for blue values. 246 254 * \param amask Bitmask for alpha values. 247 * \return Dither object , or NULL upon error.255 * \return Dither object upon success, NULL if an error occurred. 248 256 */ 249 257 cucul_dither_t *cucul_create_dither(unsigned int bpp, unsigned int w, … … 257 265 /* Minor sanity test */ 258 266 if(!w || !h || !pitch || bpp > 32 || bpp < 8) 267 { 268 #if defined(HAVE_ERRNO_H) 269 errno = EINVAL; 270 #endif 259 271 return NULL; 272 } 260 273 261 274 d = malloc(sizeof(cucul_dither_t)); 262 275 if(!d) 276 { 277 #if defined(HAVE_ERRNO_H) 278 errno = ENOMEM; 279 #endif 263 280 return NULL; 281 } 264 282 265 283 d->bpp = bpp; … … 326 344 * 0 and 4095 (0xfff). 327 345 * 346 * If an error occurs, -1 is returned and \b errno is set accordingly: 347 * - \c EINVAL Dither bits per pixel value is not 8, or one of the pixel 348 * values was outside the range 0 - 4095. 349 * 328 350 * \param d Dither object. 329 351 * \param red Array of 256 red values. … … 331 353 * \param blue Array of 256 blue values. 332 354 * \param alpha Array of 256 alpha values. 333 */ 334 void cucul_set_dither_palette(cucul_dither_t *d, 335 unsigned int red[], unsigned int green[], 336 unsigned int blue[], unsigned int alpha[]) 355 * \return 0 in case of success, -1 if an error occurred. 356 */ 357 int cucul_set_dither_palette(cucul_dither_t *d, 358 unsigned int red[], unsigned int green[], 359 unsigned int blue[], unsigned int alpha[]) 337 360 { 338 361 int i, has_alpha = 0; 339 362 340 363 if(d->bpp != 8) 341 return; 364 { 365 #if defined(HAVE_ERRNO_H) 366 errno = EINVAL; 367 #endif 368 return -1; 369 } 342 370 343 371 for(i = 0; i < 256; i++) 344 372 { 345 if(red[i] >= 0 && red[i] < 0x1000 && 346 green[i] >= 0 && green[i] < 0x1000 && 347 blue[i] >= 0 && blue[i] < 0x1000 && 348 alpha[i] >= 0 && alpha[i] < 0x1000) 373 if((red[i] | green[i] | blue[i] | alpha[i]) >= 0x1000) 349 374 { 350 d->red[i] = red[i]; 351 d->green[i] = green[i]; 352 d->blue[i] = blue[i]; 353 if(alpha[i]) 354 { 355 d->alpha[i] = alpha[i]; 356 has_alpha = 1; 357 } 375 #if defined(HAVE_ERRNO_H) 376 errno = EINVAL; 377 #endif 378 return -1; 358 379 } 359 380 } 360 381 382 for(i = 0; i < 256; i++) 383 { 384 d->red[i] = red[i]; 385 d->green[i] = green[i]; 386 d->blue[i] = blue[i]; 387 if(alpha[i]) 388 { 389 d->alpha[i] = alpha[i]; 390 has_alpha = 1; 391 } 392 } 393 361 394 d->has_alpha = has_alpha; 395 396 return 0; 362 397 } 363 398 … … 365 400 * 366 401 * Set the brightness of dither. 402 * 403 * If an error occurs, -1 is returned and \b errno is set accordingly: 404 * - \c EINVAL Brightness value was out of range. 367 405 * 368 406 * \param d Dither object. 369 407 * \param brightness brightness value. 370 */ 371 void cucul_set_dither_brightness(cucul_dither_t *d, float brightness) 408 * \return 0 in case of success, -1 if an error occurred. 409 */ 410 int cucul_set_dither_brightness(cucul_dither_t *d, float brightness) 372 411 { 373 412 /* FIXME */ 413 return 0; 374 414 } 375 415 … … 377 417 * 378 418 * Set the gamma of dither. 419 * 420 * If an error occurs, -1 is returned and \b errno is set accordingly: 421 * - \c EINVAL Gamma value was out of range. 379 422 * 380 423 * \param d Dither object. 381 424 * \param gamma Gamma value. 382 */ 383 void cucul_set_dither_gamma(cucul_dither_t *d, float gamma) 384 { 385 /* FIXME: we don't need 4096 calls to gammapow(), we can just compute 425 * \return 0 in case of success, -1 if an error occurred. 426 */ 427 int cucul_set_dither_gamma(cucul_dither_t *d, float gamma) 428 { 429 /* FIXME: we don't need 4096 calls to gammapow(), we could just compute 386 430 * 128 of them and do linear interpolation for the rest. This will 387 431 * probably speed up things a lot. */ … … 389 433 390 434 if(gamma <= 0.0) 391 return; 435 { 436 #if defined(HAVE_ERRNO_H) 437 errno = EINVAL; 438 #endif 439 return -1; 440 } 392 441 393 442 d->gamma = gamma; … … 395 444 for(i = 0; i < 4096; i++) 396 445 d->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma); 446 447 return 0; 397 448 } 398 449 399 450 /** \brief Invert colors of dither 400 451 * 401 * Invert colors of dither 452 * Invert colors of dither. 453 * 454 * This function never fails. 402 455 * 403 456 * \param d Dither object. 404 457 * \param value 0 for normal behaviour, 1 for invert 405 */ 406 void cucul_set_dither_invert(cucul_dither_t *d, int value) 458 * \return This function always returns 0. 459 */ 460 int cucul_set_dither_invert(cucul_dither_t *d, int value) 407 461 { 408 462 d->invert = value ? 1 : 0; 463 464 return 0; 409 465 } 410 466 … … 412 468 * 413 469 * Set the contrast of dither. 470 * 471 * If an error occurs, -1 is returned and \b errno is set accordingly: 472 * - \c EINVAL Contrast value was out of range. 414 473 * 415 474 * \param d Dither object. 416 475 * \param contrast contrast value. 417 */ 418 void cucul_set_dither_contrast(cucul_dither_t *d, float contrast) 476 * \return 0 in case of success, -1 if an error occurred. 477 */ 478 int cucul_set_dither_contrast(cucul_dither_t *d, float contrast) 419 479 { 420 480 /* FIXME */ 481 return 0; 421 482 } 422 483 … … 428 489 * \li \c "none": no antialiasing. 429 490 * 430 * \li \c "prefilter": simple prefilter antialiasing. This is the default 431 * value. 491 * \li \c "prefilter" or \c "default": simple prefilter antialiasing. This 492 * is the default value. 493 * 494 * If an error occurs, -1 is returned and \b errno is set accordingly: 495 * - \c EINVAL Invalid antialiasing mode. 432 496 * 433 497 * \param d Dither object. 434 498 * \param str A string describing the antialiasing method that will be used 435 499 * for the dithering. 436 */ 437 void cucul_set_dither_antialias(cucul_dither_t *d, char const *str) 500 * \return 0 in case of success, -1 if an error occurred. 501 */ 502 int cucul_set_dither_antialias(cucul_dither_t *d, char const *str) 438 503 { 439 504 if(!strcasecmp(str, "none")) 440 505 d->antialias = 0; 441 else /* "prefilter" is the default */506 else if(!strcasecmp(str, "prefilter") || !strcasecmp(str, "default")) 442 507 d->antialias = 1; 508 else 509 { 510 #if defined(HAVE_ERRNO_H) 511 errno = EINVAL; 512 #endif 513 return -1; 514 } 515 516 return 0; 443 517 } 444 518 … … 451 525 * language description for that antialiasing method. 452 526 * 527 * This function never fails. 528 * 453 529 * \param d Dither object. 454 530 * \return An array of strings. … … 486 562 * background. 487 563 * 488 * \li \c "full16": use the 16 ANSI colours for both the characters and the 489 * background. This is the default value. 564 * \li \c "full16" or \c "default": use the 16 ANSI colours for both the 565 * characters and the background. This is the default value. 566 * 567 * If an error occurs, -1 is returned and \b errno is set accordingly: 568 * - \c EINVAL Invalid colour set. 490 569 * 491 570 * \param d Dither object. 492 571 * \param str A string describing the colour set that will be used 493 572 * for the dithering. 494 */ 495 void cucul_set_dither_color(cucul_dither_t *d, char const *str) 573 * \return 0 in case of success, -1 if an error occurred. 574 */ 575 int cucul_set_dither_color(cucul_dither_t *d, char const *str) 496 576 { 497 577 if(!strcasecmp(str, "mono")) … … 507 587 else if(!strcasecmp(str, "full8")) 508 588 d->color_mode = COLOR_MODE_FULL8; 509 else /* "full16" is the default */589 else if(!strcasecmp(str, "full16") || !strcasecmp(str, "default")) 510 590 d->color_mode = COLOR_MODE_FULL16; 591 else 592 { 593 #if defined(HAVE_ERRNO_H) 594 errno = EINVAL; 595 #endif 596 return -1; 597 } 598 599 return 0; 511 600 } 512 601 … … 518 607 * cucul_set_dither_color(), and a string containing the natural 519 608 * language description for that colour mode. 609 * 610 * This function never fails. 520 611 * 521 612 * \param d Dither object. … … 545 636 * dither. Valid values for \c str are: 546 637 * 547 * \li \c "ascii": use only ASCII characters. This is the default value. 638 * \li \c "ascii" or "default": use only ASCII characters. This is the 639 * default value. 548 640 * 549 641 * \li \c "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592 … … 554 646 * characters are only found in the Unicode set. 555 647 * 648 * If an error occurs, -1 is returned and \b errno is set accordingly: 649 * - \c EINVAL Invalid character set. 650 * 556 651 * \param d Dither object. 557 652 * \param str A string describing the characters that need to be used 558 653 * for the dithering. 559 */ 560 void cucul_set_dither_charset(cucul_dither_t *d, char const *str) 654 * \return 0 in case of success, -1 if an error occurred. 655 */ 656 int cucul_set_dither_charset(cucul_dither_t *d, char const *str) 561 657 { 562 658 if(!strcasecmp(str, "shades")) … … 570 666 d->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs); 571 667 } 572 else /* "ascii" is the default */668 else if(!strcasecmp(str, "ascii") || !strcasecmp(str, "default")) 573 669 { 574 670 d->glyphs = ascii_glyphs; 575 671 d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs); 576 672 } 673 else 674 { 675 #if defined(HAVE_ERRNO_H) 676 errno = EINVAL; 677 #endif 678 return -1; 679 } 680 681 return 0; 577 682 } 578 683 … … 585 690 * language description for that character set. 586 691 * 692 * This function never fails. 693 * 587 694 * \param d Dither object. 588 695 * \return An array of strings. … … 619 726 * \li \c "fstein": use Floyd-Steinberg dithering. This is the default value. 620 727 * 728 * If an error occurs, -1 is returned and \b errno is set accordingly: 729 * - \c EINVAL Unknown dithering mode. 730 * 621 731 * \param d Dither object. 622 732 * \param str A string describing the method that needs to be used 623 733 * for the dithering. 624 */ 625 void cucul_set_dither_mode(cucul_dither_t *d, char const *str) 734 * \return 0 in case of success, -1 if an error occurred. 735 */ 736 int cucul_set_dither_mode(cucul_dither_t *d, char const *str) 626 737 { 627 738 if(!strcasecmp(str, "none")) … … 655 766 d->increment_dither = increment_random_dither; 656 767 } 657 else /* "fstein" is the default */768 else if(!strcasecmp(str, "fstein") || !strcasecmp(str, "default")) 658 769 { 659 770 d->init_dither = init_fstein_dither; … … 661 772 d->increment_dither = increment_fstein_dither; 662 773 } 774 else 775 { 776 #if defined(HAVE_ERRNO_H) 777 errno = EINVAL; 778 #endif 779 return -1; 780 } 781 782 return 0; 663 783 } 664 784 … … 670 790 * cucul_set_dither_dithering(), and a string containing the natural 671 791 * language description for that dithering method. 792 * 793 * This function never fails. 672 794 * 673 795 * \param d Dither object. … … 695 817 * and will be stretched to the text area. 696 818 * 819 * This function never fails. 820 * 697 821 * \param cv A handle to the libcucul canvas. 698 822 * \param x X coordinate of the upper-left corner of the drawing area. … … 702 826 * \param d Dither object to be drawn. 703 827 * \param pixels Bitmap's pixels. 704 */ 705 void cucul_dither_bitmap(cucul_canvas_t *cv, int x, int y, int w, int h, 706 cucul_dither_t const *d, void *pixels) 828 * \return This function always returns 0. 829 */ 830 int cucul_dither_bitmap(cucul_canvas_t *cv, int x, int y, int w, int h, 831 cucul_dither_t const *d, void *pixels) 707 832 { 708 833 int *floyd_steinberg, *fs_r, *fs_g, *fs_b; … … 712 837 713 838 if(!d || !pixels) 714 return ;839 return 0; 715 840 716 841 x1 = x; x2 = x + w - 1; … … 941 1066 942 1067 free(floyd_steinberg); 1068 1069 return 0; 943 1070 } 944 1071 … … 947 1074 * Free the memory allocated by cucul_create_dither(). 948 1075 * 1076 * This function never fails. 1077 * 949 1078 * \param d Dither object. 950 */ 951 void cucul_free_dither(cucul_dither_t *d) 1079 * \return This function always returns 0. 1080 */ 1081 int cucul_free_dither(cucul_dither_t *d) 952 1082 { 953 1083 if(!d) 954 return ;1084 return 0; 955 1085 956 1086 free(d); 1087 1088 return 0; 957 1089 } 958 1090 -
libcaca/trunk/cucul/export.c
r896 r920 21 21 22 22 #if !defined(__KERNEL__) 23 # if defined(HAVE_ERRNO_H) 24 # include <errno.h> 25 # endif 23 26 # include <stdlib.h> 24 27 # include <stdio.h> … … 64 67 * \li \c "tga": export a TGA image. 65 68 * 69 * If an error occurs, NULL is returned and \b errno is set accordingly: 70 * - \c EINVAL Invalid format requested. 71 * - \c ENOMEM Not enough memory to allocate output buffer. 72 * 66 73 * \param cv A libcucul canvas 67 74 * \param format A string describing the requested output format. 75 * \return A libcucul buffer, or NULL in case of error. 68 76 */ 69 77 cucul_buffer_t * cucul_export_canvas(cucul_canvas_t *cv, char const *format) … … 72 80 73 81 ex = malloc(sizeof(cucul_buffer_t)); 82 if(!ex) 83 { 84 #if defined(HAVE_ERRNO_H) 85 errno = ENOMEM; 86 #endif 87 return NULL; 88 } 89 74 90 ex->size = 0; 75 91 ex->data = NULL; … … 96 112 { 97 113 free(ex); 114 #if defined(HAVE_ERRNO_H) 115 errno = EINVAL; 116 #endif 98 117 return NULL; 99 118 } … … 108 127 * the export format, to be used with cucul_export_canvas(), and a string 109 128 * containing the natural language description for that export format. 129 * 130 * This function never fails. 110 131 * 111 132 * \return An array of strings. -
libcaca/trunk/cucul/font.c
r865 r920 27 27 # elif defined(HAVE_NETINET_IN_H) 28 28 # include <netinet/in.h> 29 # endif 30 # if defined(HAVE_ERRNO_H) 31 # include <errno.h> 29 32 # endif 30 33 # include <stdio.h> … … 109 112 * program until the font handle has been freed with cucul_free_font(). 110 113 * 114 * If an error occurs, NULL is returned and \b errno is set accordingly: 115 * - \c ENOENT Requested built-in font does not exist. 116 * - \c EINVAL Invalid font data in memory area. 117 * - \c ENOMEM Not enough memory to allocate font structure. 118 * 111 119 * \param data The memory area containing the font or its name. 112 120 * \param size The size of the memory area, or 0 if the font name is given. … … 127 135 #endif 128 136 137 #if defined(HAVE_ERRNO_H) 138 errno = ENOENT; 139 #endif 129 140 return NULL; 130 141 } 131 142 132 143 if(size < sizeof(struct font_header)) 144 { 145 #if defined(HAVE_ERRNO_H) 146 errno = EINVAL; 147 #endif 133 148 return NULL; 149 } 134 150 135 151 f = malloc(sizeof(cucul_font_t)); 152 if(!f) 153 { 154 #if defined(HAVE_ERRNO_H) 155 errno = ENOMEM; 156 #endif 157 return NULL; 158 } 159 136 160 f->private = (void *)(uintptr_t)data; 137 161 … … 153 177 { 154 178 free(f); 179 #if defined(HAVE_ERRNO_H) 180 errno = EINVAL; 181 #endif 155 182 return NULL; 156 183 } 157 184 158 185 f->block_list = malloc(f->header.blocks * sizeof(struct block_info)); 186 if(!f->block_list) 187 { 188 free(f); 189 #if defined(HAVE_ERRNO_H) 190 errno = ENOMEM; 191 #endif 192 return NULL; 193 } 194 159 195 memcpy(f->block_list, 160 196 f->private + 8 + sizeof(struct font_header), … … 172 208 free(f->block_list); 173 209 free(f); 210 #if defined(HAVE_ERRNO_H) 211 errno = EINVAL; 212 #endif 174 213 return NULL; 175 214 } … … 177 216 178 217 f->glyph_list = malloc(f->header.glyphs * sizeof(struct glyph_info)); 218 if(!f->glyph_list) 219 { 220 free(f->block_list); 221 free(f); 222 #if defined(HAVE_ERRNO_H) 223 errno = ENOMEM; 224 #endif 225 return NULL; 226 } 227 179 228 memcpy(f->glyph_list, 180 229 f->private + 8 + sizeof(struct font_header) … … 195 244 free(f->block_list); 196 245 free(f); 246 #if defined(HAVE_ERRNO_H) 247 errno = EINVAL; 248 #endif 197 249 return NULL; 198 250 } … … 208 260 * Return a list of available builtin fonts. The list is a NULL-terminated 209 261 * array of strings. 262 * 263 * This function never fails. 210 264 * 211 265 * \return An array of strings. … … 227 281 * This function returns the maximum value for the current font's glyphs 228 282 * 283 * This function never fails. 284 * 229 285 * \param f The font, as returned by cucul_load_font() 230 286 * \return The maximum glyph width. … … 238 294 * 239 295 * This function returns the maximum value for the current font's glyphs 296 * 297 * This function never fails. 240 298 * 241 299 * \param f The font, as returned by cucul_load_font() … … 254 312 * cucul_load_font() can be freed. 255 313 * 314 * This function never fails. 315 * 256 316 * \param f The font, as returned by cucul_load_font() 257 */ 258 void cucul_free_font(cucul_font_t *f) 317 * \return This function always returns 0. 318 */ 319 int cucul_free_font(cucul_font_t *f) 259 320 { 260 321 free(f->glyph_list); 261 322 free(f->block_list); 262 323 free(f); 324 325 return 0; 263 326 } 264 327 … … 275 338 * Glyphs that do not fit in the image buffer are currently not rendered at 276 339 * all. They may be cropped instead in future versions. 340 * 341 * This function never fails. 277 342 * 278 343 * \param cv The canvas to render … … 282 347 * \param height The height (in pixels) of the image buffer 283 348 * \param pitch The pitch (in bytes) of an image buffer line. 284 */ 285 void cucul_render_canvas(cucul_canvas_t *cv, cucul_font_t *f, 286 void *buf, unsigned int width, 287 unsigned int height, unsigned int pitch) 349 * \return This function always returns 0. 350 */ 351 int cucul_render_canvas(cucul_canvas_t *cv, cucul_font_t *f, 352 void *buf, unsigned int width, 353 unsigned int height, unsigned int pitch) 288 354 { 289 355 uint8_t *glyph = NULL; … … 380 446 if(f->header.bpp != 8) 381 447 free(glyph); 448 449 return 0; 382 450 } 383 451 -
libcaca/trunk/cucul/import.c
r918 r920 20 20 21 21 #if !defined(__KERNEL__) 22 # if defined(HAVE_ERRNO_H) 23 # include <errno.h> 24 # endif 22 25 # include <stdio.h> 23 26 # include <stdlib.h> … … 44 47 /** \brief Import a buffer into a canvas 45 48 * 46 * This function imports a libcucul buffer (cucul_load_memory()/cucul_load_file())47 * into an internal libcucul canvas.49 * This function imports a libcucul buffer as returned by cucul_load_memory() 50 * or cucul_load_file() into an internal libcucul canvas. 48 51 * 49 52 * Valid values for \c format are: … … 54 57 * 55 58 * \li \c "caca": import native libcaca files. 59 * 60 * If an error occurs, NULL is returned and \b errno is set accordingly: 61 * - \c ENOMEM Not enough memory to allocate canvas. 62 * - \c EINVAL Invalid format requested. 56 63 * 57 64 * \param buffer A \e libcucul buffer containing the data to be loaded … … 64 71 char const *buf = (char const*)buffer->data; 65 72 66 if(buffer->size == 0 || buffer->data == NULL)67 return NULL;68 69 73 if(!strcasecmp("caca", format)) 70 74 return import_caca(buffer->data, buffer->size); … … 76 80 /* Autodetection */ 77 81 if(!strcasecmp("", format)) 78 { 79 unsigned int i=0; 80 /* if 4 first letters are CACA */ 81 if(buffer->size >= 4 && 82 buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A') 83 return import_caca(buffer->data, buffer->size); 84 85 /* If we find ESC[ argv, we guess it's an ANSI file */ 86 while(i < buffer->size - 1) 87 { 88 if((buf[i] == 0x1b) && (buf[i+1] == '[')) 89 return import_ansi(buffer->data, buffer->size); 90 i++; 91 } 92 93 /* Otherwise, import it as text */ 94 return import_text(buffer->data, buffer->size); 95 } 82 { 83 unsigned int i; 84 85 /* If 4 first letters are CACA */ 86 if(buffer->size >= 4 && 87 buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A') 88 return import_caca(buffer->data, buffer->size); 89 90 /* If we find ESC[ argv, we guess it's an ANSI file */ 91 for(i = 0; i < buffer->size - 1; i++) 92 if((buf[i] == 0x1b) && (buf[i + 1] == '[')) 93 return import_ansi(buffer->data, buffer->size); 94 95 /* Otherwise, import it as text */ 96 return import_text(buffer->data, buffer->size); 97 } 98 99 #if defined(HAVE_ERRNO_H) 100 errno = EINVAL; 101 #endif 96 102 return NULL; 97 103 } … … 103 109 * the import format, to be used with cucul_import_canvas(), and a string 104 110 * containing the natural language description for that import format. 111 * 112 * This function never fails. 105 113 * 106 114 * \return An array of strings. … … 131 139 132 140 if(size < 16) 133 return NULL;141 goto invalid_caca; 134 142 135 143 if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A') 136 return NULL;144 goto invalid_caca; 137 145 138 146 if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V') 139 return NULL;147 goto invalid_caca; 140 148 141 149 width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16) … … 145 153 146 154 if(!width || !height) 155 goto invalid_caca; 156 157 if(size != 16 + width * height * 8) 158 goto invalid_caca; 159 160 cv = cucul_create_canvas(width, height); 161 162 if(!cv) 163 { 164 #if defined(HAVE_ERRNO_H) 165 errno = ENOMEM; 166 #endif 147 167 return NULL; 148 149 if(size != 16 + width * height * 8) 150 return NULL; 151 152 cv = cucul_create_canvas(width, height); 153 154 if(!cv) 155 return NULL; 168 } 156 169 157 170 for(n = height * width; n--; ) … … 168 181 169 182 return cv; 183 184 invalid_caca: 185 #if defined(HAVE_ERRNO_H) 186 errno = EINVAL; 187 #endif 188 return NULL; 170 189 } 171 190 … … 177 196 178 197 cv = cucul_create_canvas(width, height); 198 if(!cv) 199 { 200 #if defined(HAVE_ERRNO_H) 201 errno = ENOMEM; 202 #endif 203 return NULL; 204 } 205 179 206 cucul_set_color(cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_TRANSPARENT); 180 207 181 208 for(i = 0; i < size; i++) 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 { 210 unsigned char ch = *text++; 211 212 if(ch == '\r') 213 continue; 214 215 if(ch == '\n') 216 { 217 x = 0; 218 y++; 219 continue; 220 } 221 222 if(x >= width || y >= height) 223 { 224 if(x >= width) 225 width = x + 1; 226 227 if(y >= height) 228 height = y + 1; 229 230 cucul_set_canvas_size(cv, width, height); 231 } 232 233 cucul_putchar(cv, x, y, ch); 234 x++; 235 } 209 236 210 237 return cv; … … 221 248 222 249 cv = cucul_create_canvas(width, height); 250 if(!cv) 251 { 252 #if defined(HAVE_ERRNO_H) 253 errno = ENOMEM; 254 #endif 255 return NULL; 256 } 257 223 258 ansi_parse_grcm(cv, &grcm, 1, &dummy); 224 259 225 260 for(i = 0; i < size; i += skip) 226 { 227 skip = 1; 228 229 /* Wrap long lines */ 230 if((unsigned int)x >= width) 261 { 262 skip = 1; 263 264 /* Wrap long lines */ 265 if((unsigned int)x >= width) 266 { 267 x = 0; 268 y++; 269 } 270 271 if(buffer[i] == '\x1a' && size - i >= 8 272 && !memcmp(buffer + i + 1, "SAUCE00", 7)) 273 break; /* End before SAUCE data */ 274 275 if(buffer[i] == '\r') 276 continue; /* DOS sucks */ 277 278 if(buffer[i] == '\n') 279 { 280 x = 0; 281 y++; 282 continue; 283 } 284 285 /* Interpret escape commands, as per Standard ECMA-48 "Control 286 * Functions for Coded Character Sets", 5.4. Control sequences. */ 287 if(buffer[i] == '\x1b' && buffer[i + 1] == '[') 288 { 289 unsigned int argc = 0, argv[101]; 290 unsigned int param, inter, final; 291 292 /* Compute offsets to parameter bytes, intermediate bytes and 293 * to the final byte. Only the final byte is mandatory, there 294 * can be zero of the others. 295 * 0 param=2 inter final final+1 296 * +-----+------------------+---------------------+-----------------+ 297 * | CSI | parameter bytes | intermediate bytes | final byte | 298 * | | 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | 299 * | ^[[ | 0123456789:;<=>? | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ | 300 * +-----+------------------+---------------------+-----------------+ 301 */ 302 param = 2; 303 304 for(inter = param; i + inter < size; inter++) 305 if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f) 306 break; 307 308 for(final = inter; i + final < size; final++) 309 if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f) 310 break; 311 312 if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e) 313 break; /* Invalid Final Byte */ 314 315 skip += final; 316 317 /* Sanity checks */ 318 if(param < inter && buffer[i + param] >= 0x3c) 319 { 320 fprintf(stderr, "private sequence \"^[[%.*s\"\n", 321 final - param + 1, buffer + i + param); 322 continue; /* Private sequence, skip it entirely */ 323 } 324 325 if(final - param > 100) 326 continue; /* Suspiciously long sequence, skip it */ 327 328 /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string 329 * format */ 330 if(param < inter) 331 { 332 argv[0] = 0; 333 for(j = param; j < inter; j++) 231 334 { 335 if(buffer[i + j] == ';') 336 argv[++argc] = 0; 337 else if(buffer[i + j] >= '0' && buffer[i + j] <= '9') 338 argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0'); 339 } 340 argc++; 341 } 342 343 /* Interpret final byte. The code representations are given in 344 * ECMA-48 5.4: Control sequences, and the code definitions are 345 * given in ECMA-48 8.3: Definition of control functions. */ 346 switch(buffer[i + final]) 347 { 348 case 'f': /* CUP - Cursor Position */ 349 case 'H': /* HVP - Character And Line Position */ 350 x = (argc > 1) ? argv[1] - 1 : 0; 351 y = (argc > 0) ? argv[0] - 1 : 0; 352 break; 353 case 'A': /* CUU - Cursor Up */ 354 y -= argc ? argv[0] : 1; 355 if(y < 0) 356 y = 0; 357 break; 358 case 'B': /* CUD - Cursor Down */ 359 y += argc ? argv[0] : 1; 360 break; 361 case 'C': /* CUF - Cursor Right */ 362 x += argc ? argv[0] : 1; 363 break; 364 case 'D': /* CUB - Cursor Left */ 365 x -= argc ? argv[0] : 1; 366 if(x < 0) 232 367 x = 0; 233 y++; 234 } 235 236 if(buffer[i] == '\x1a' && size - i >= 8 237 && !memcmp(buffer + i + 1, "SAUCE00", 7)) 238 break; /* End before SAUCE data */ 239 240 if(buffer[i] == '\r') 241 continue; /* DOS sucks */ 242 243 if(buffer[i] == '\n') 244 { 245 x = 0; 246 y++; 247 continue; 248 } 249 250 /* Interpret escape commands, as per Standard ECMA-48 "Control 251 * Functions for Coded Character Sets", 5.4. Control sequences. */ 252 if(buffer[i] == '\x1b' && buffer[i + 1] == '[') 253 { 254 unsigned int argc = 0, argv[101]; 255 unsigned int param, inter, final; 256 257 /* Compute offsets to parameter bytes, intermediate bytes and 258 * to the final byte. Only the final byte is mandatory, there 259 * can be zero of the others. 260 * 0 param=2 inter final final+1 261 * +-----+------------------+---------------------+-----------------+ 262 * | CSI | parameter bytes | intermediate bytes | final byte | 263 * | | 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | 264 * | ^[[ | 0123456789:;<=>? | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ | 265 * +-----+------------------+---------------------+-----------------+ 266 */ 267 param = 2; 268 269 for(inter = param; i + inter < size; inter++) 270 if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f) 271 break; 272 273 for(final = inter; i + final < size; final++) 274 if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f) 275 break; 276 277 if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e) 278 break; /* Invalid Final Byte */ 279 280 skip += final; 281 282 /* Sanity checks */ 283 if(param < inter && buffer[i + param] >= 0x3c) 284 { 285 fprintf(stderr, "private sequence \"^[[%.*s\"\n", 286 final - param + 1, buffer + i + param); 287 continue; /* Private sequence, skip it entirely */ 288 } 289 290 if(final - param > 100) 291 continue; /* Suspiciously long sequence, skip it */ 292 293 /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string 294 * format */ 295 if(param < inter) 296 { 297 argv[0] = 0; 298 for(j = param; j < inter; j++) 299 { 300 if(buffer[i + j] == ';') 301 argv[++argc] = 0; 302 else if(buffer[i + j] >= '0' && buffer[i + j] <= '9') 303 argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0'); 304 } 305 argc++; 306 } 307 308 /* Interpret final byte. The code representations are given in 309 * ECMA-48 5.4: Control sequences, and the code definitions are 310 * given in ECMA-48 8.3: Definition of control functions. */ 311 switch(buffer[i + final]) 312 { 313 case 'f': /* CUP - Cursor Position */ 314 case 'H': /* HVP - Character And Line Position */ 315 x = (argc > 1) ? argv[1] - 1 : 0; 316 y = (argc > 0) ? argv[0] - 1 : 0; 317 break; 318 case 'A': /* CUU - Cursor Up */ 319 y -= argc ? argv[0] : 1; 320 if(y < 0) 321 y = 0; 322 break; 323 case 'B': /* CUD - Cursor Down */ 324 y += argc ? argv[0] : 1; 325 break; 326 case 'C': /* CUF - Cursor Right */ 327 x += argc ? argv[0] : 1; 328 break; 329 case 'D': /* CUB - Cursor Left */ 330 x -= argc ? argv[0] : 1; 331 if(x < 0) 332 x = 0; 333 break; 334 case 's': /* Private (save cursor position) */ 335 save_x = x; 336 save_y = y; 337 break; 338 case 'u': /* Private (reload cursor positin) */ 339 x = save_x; 340 y = save_y; 341 break; 342 case 'J': /* ED - Erase In Page */ 343 if(argv[0] == 2) 344 x = y = 0; 345 break; 346 case 'K': /* EL - Erase In Line */ 347 for(j = x; j < width; j++) 348 _cucul_putchar32(cv, j, y, (uint32_t)' '); 349 x = width; 350 break; 351 case 'm': /* SGR - Select Graphic Rendition */ 352 ansi_parse_grcm(cv, &grcm, argc, argv); 353 break; 354 default: 355 fprintf(stderr, "unknown command %c\n", buffer[i + final]); 356 break; 357 } 358 359 continue; 360 } 361 362 /* We're going to paste a character. First make sure the canvas 363 * is big enough. */ 364 if((unsigned int)y >= height) 365 { 366 height = y + 1; 367 cucul_set_canvas_size(cv, width, height); 368 } 369 370 /* Now paste our character */ 371 _cucul_putchar32(cv, x, y, _cucul_cp437_to_utf32(buffer[i])); 372 x++; 373 } 368 break; 369 case 's': /* Private (save cursor position) */ 370 save_x = x; 371 save_y = y; 372 break; 373 case 'u': /* Private (reload cursor positin) */ 374 x = save_x; 375 y = save_y; 376 break; 377 case 'J': /* ED - Erase In Page */ 378 if(argv[0] == 2) 379 x = y = 0; 380 break; 381 case 'K': /* EL - Erase In Line */ 382 for(j = x; j < width; j++) 383 _cucul_putchar32(cv, j, y, (uint32_t)' '); 384 x = width; 385 break; 386 case 'm': /* SGR - Select Graphic Rendition */ 387 ansi_parse_grcm(cv, &grcm, argc, argv); 388 break; 389 default: 390 fprintf(stderr, "unknown command %c\n", buffer[i + final]); 391 break; 392 } 393 394 continue; 395 } 396 397 /* We're going to paste a character. First make sure the canvas 398 * is big enough. */ 399 if((unsigned int)y >= height) 400 { 401 height = y + 1; 402 cucul_set_canvas_size(cv, width, height); 403 } 404 405 /* Now paste our character */ 406 _cucul_putchar32(cv, x, y, _cucul_cp437_to_utf32(buffer[i])); 407 x++; 408 } 374 409 375 410 return cv; … … 382 417 { 383 418 static uint8_t const ansi2cucul[] = 384 385 386 387 388 389 419 { 420 CUCUL_COLOR_BLACK, CUCUL_COLOR_RED, 421 CUCUL_COLOR_GREEN, CUCUL_COLOR_BROWN, 422 CUCUL_COLOR_BLUE, CUCUL_COLOR_MAGENTA, 423 CUCUL_COLOR_CYAN, CUCUL_COLOR_LIGHTGRAY 424 }; 390 425 391 426 unsigned int j; … … 393 428 394 429 for(j = 0; j < argc; j++) 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 430 { 431 /* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */ 432 if(argv[j] >= 30 && argv[j] <= 37) 433 g->fg = ansi2cucul[argv[j] - 30]; 434 else if(argv[j] >= 40 && argv[j] <= 47) 435 g->bg = ansi2cucul[argv[j] - 40]; 436 else if(argv[j] >= 90 && argv[j] <= 97) 437 g->fg = ansi2cucul[argv[j] - 90] + 8; 438 else if(argv[j] >= 100 && argv[j] <= 107) 439 g->bg = ansi2cucul[argv[j] - 100] + 8; 440 else switch(argv[j]) 441 { 442 case 0: /* default rendition */ 443 g->fg = CUCUL_COLOR_DEFAULT; 444 g->bg = CUCUL_COLOR_DEFAULT; 445 g->bold = g->negative = g->concealed = 0; 446 break; 447 case 1: /* bold or increased intensity */ 448 g->bold = 1; 449 break; 450 case 4: /* singly underlined */ 451 break; 452 case 5: /* slowly blinking (less then 150 per minute) */ 453 break; 454 case 7: /* negative image */ 455 g->negative = 1; 456 break; 457 case 8: /* concealed characters */ 458 g->concealed = 1; 459 break; 460 case 22: /* normal colour or normal intensity (neither bold nor faint) */ 461 g->bold = 0; 462 break; 463 case 28: /* revealed characters */ 464 g->concealed = 0; 465 break; 466 case 39: /* default display colour (implementation-defined) */ 467 g->fg = CUCUL_COLOR_DEFAULT; 468 break; 469 case 49: /* default background colour (implementation-defined) */ 470 g->bg = CUCUL_COLOR_DEFAULT; 471 break; 472 default: 473 fprintf(stderr, "unknown sgr %i\n", argv[j]); 474 break; 475 } 476 } 442 477 443 478 if(g->concealed) 444 445 446 479 { 480 myfg = mybg = CUCUL_COLOR_TRANSPARENT; 481 } 447 482 else 448 449 450 451 452 453 454 455 456 457 458 459 483 { 484 myfg = g->negative ? g->bg : g->fg; 485 mybg = g->negative ? g->fg : g->bg; 486 487 if(g->bold) 488 { 489 if(myfg < 8) 490 myfg += 8; 491 else if(myfg == CUCUL_COLOR_DEFAULT) 492 myfg = CUCUL_COLOR_WHITE; 493 } 494 } 460 495 461 496 cucul_set_color(cv, myfg, mybg); -
libcaca/trunk/cucul/sprite.c
r859 r920 23 23 # include <stdlib.h> 24 24 # include <string.h> 25 # if defined(HAVE_ERRNO_H) 26 # include <errno.h> 27 # endif 25 28 #endif 26 29 … … 31 34 * 32 35 * This function returns the current canvas frame count. 36 * 37 * This function never fails. 33 38 * 34 39 * \param cv A libcucul canvas … … 48 53 * If the frame index is outside the canvas' frame range, nothing happens. 49 54 * 55 * If an error occurs, -1 is returned and \b errno is set accordingly: 56 * - \c EINVAL Requested frame is out of range. 57 * 50 58 * \param cv A libcucul canvas 51 59 * \param frame The canvas frame to activate 60 * \return 0 in case of success, -1 if an error occurred. 52 61 */ 53 voidcucul_set_canvas_frame(cucul_canvas_t *cv, unsigned int frame)62 int cucul_set_canvas_frame(cucul_canvas_t *cv, unsigned int frame) 54 63 { 55 64 if(frame >= cv->framecount) 56 return; 65 { 66 #if defined(HAVE_ERRNO_H) 67 errno = EINVAL; 68 #endif 69 return -1; 70 } 57 71 58 72 cv->frame = frame; … … 60 74 cv->chars = cv->allchars[cv->frame]; 61 75 cv->attr = cv->allattr[cv->frame]; 76 77 return 0; 62 78 } 63 79 … … 75 91 * to the insertion. 76 92 * 93 * If an error occurs, -1 is returned and \b errno is set accordingly: 94 * - \c ENOMEM Not enough memory to allocate new frame. 95 * 77 96 * \param cv A libcucul canvas 78 97 * \param frame The index where to insert the new frame 98 * \return 0 in case of success, -1 if an error occurred. 79 99 */ 80 voidcucul_create_canvas_frame(cucul_canvas_t *cv, unsigned int frame)100 int cucul_create_canvas_frame(cucul_canvas_t *cv, unsigned int frame) 81 101 { 82 102 unsigned int size = cv->width * cv->height * sizeof(uint32_t); … … 106 126 cv->chars = cv->allchars[cv->frame]; 107 127 cv->attr = cv->allattr[cv->frame]; 128 129 return 0; 108 130 } 109 131 … … 124 146 * renumbered due to the deletion. 125 147 * 148 * If an error occurs, -1 is returned and \b errno is set accordingly: 149 * - \c EINVAL Requested frame is out of range, or attempt to delete the 150 * last frame of the canvas. 151 * 126 152 * \param cv A libcucul canvas 127 153 * \param frame The index of the frame to delete 154 * \return 0 in case of success, -1 if an error occurred. 128 155 */ 129 voidcucul_free_canvas_frame(cucul_canvas_t *cv, unsigned int frame)156 int cucul_free_canvas_frame(cucul_canvas_t *cv, unsigned int frame) 130 157 { 131 158 unsigned int f; 132 159 133 160 if(frame >= cv->framecount) 134 return; 161 { 162 #if defined(HAVE_ERRNO_H) 163 errno = EINVAL; 164 #endif 165 return -1; 166 } 135 167 136 168 if(cv->framecount == 1) 137 return; 169 { 170 #if defined(HAVE_ERRNO_H) 171 errno = EINVAL; 172 #endif 173 return -1; 174 } 138 175 139 176 free(cv->allchars[frame]); … … 157 194 cv->chars = cv->allchars[cv->frame]; 158 195 cv->attr = cv->allattr[cv->frame]; 196 197 return 0; 159 198 } 160 199 -
libcaca/trunk/cucul/transform.c
r859 r920 34 34 * becomes cyan, etc.) without changing the characters in it. 35 35 * 36 * This function never fails. 37 * 36 38 * \param cv The canvas to invert. 37 */ 38 void cucul_invert(cucul_canvas_t *cv) 39 * \return This function always returns 0. 40 */ 41 int cucul_invert(cucul_canvas_t *cv) 39 42 { 40 43 uint32_t *attr = cv->attr; … … 46 49 attr++; 47 50 } 51 52 return 0; 48 53 } 49 54 … … 53 58 * look like the mirrored version wherever possible. 54 59 * 60 * This function never fails. 61 * 55 62 * \param cv The canvas to flip. 56 */ 57 void cucul_flip(cucul_canvas_t *cv) 63 * \return This function always returns 0. 64 */ 65 int cucul_flip(cucul_canvas_t *cv) 58 66 { 59 67 unsigned int y; … … 83 91 *cleft = flipchar(*cleft); 84 92 } 93 94 return 0; 85 95 } 86 96 … … 90 100 * look like the mirrored version wherever possible. 91 101 * 102 * This function never fails. 103 * 92 104 * \param cv The canvas to flop. 93 */ 94 void cucul_flop(cucul_canvas_t *cv) 105 * \return This function always returns 0. 106 */ 107 int cucul_flop(cucul_canvas_t *cv) 95 108 { 96 109 unsigned int x; … … 121 134 *ctop = flopchar(*ctop); 122 135 } 136 137 return 0; 123 138 } 124 139 … … 129 144 * possible. 130 145 * 146 * This function never fails. 147 * 131 148 * \param cv The canvas to rotate. 132 */ 133 void cucul_rotate(cucul_canvas_t *cv) 149 * \return This function always returns 0. 150 */ 151 int cucul_rotate(cucul_canvas_t *cv) 134 152 { 135 153 uint32_t *cbegin = cv->chars; … … 154 172 if(cbegin == cend) 155 173 *cbegin = rotatechar(*cbegin); 174 175 return 0; 156 176 } 157 177
Note: See TracChangeset
for help on using the changeset viewer.