1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 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 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 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 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
|
/* -*- mode:c; c-file-style:"ruby" -*- */
/*
=begin
= Summary
Ruby extension for codeset conversion.
== License
$Revision: 0.4.5.0 $
$Copyleft: (c) 1999-2001 Nobuyoshi.Nakada <nobu.nokada@softhome.net> $
This library is free software; you can redistribute it and/or
modify it under the terms of
((<the GNU Lesser General Public License|URL:http://www.gnu.org/copyleft/lesser.txt>))
as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but ((*WITHOUT ANY WARRANTY*)); without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
((<the GNU Lesser General Public License|URL:http://www.gnu.org/copyleft/lesser.txt>))
for more details.
= Abstract
Iconv is a wrapper class for UNIX 95 (({iconv()})) function family, which
translates string between various coding systems.
See ((<Open Group|URL:http://www.opengroup.org/>))'s on-line documents for more details.
* ((<iconv.h|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.h.html>))
* ((<iconv_open()|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_open.html>))
* ((<iconv()|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.html>))
* ((<iconv_close()|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_close.html>))
Which coding systems are available, it depends on the platform.
=end
*/
#include <errno.h>
#include <iconv.h>
#include <assert.h>
#include "ruby.h"
#include "intern.h"
static const char rcsid[] = "$Id: iconv.c,v 0.4.5.0 2001/11/15 23:50:14 nobu Exp $";
/* Invalid value for iconv_t is -1 but 0 for VALUE, I hope VALUE is
big enough to keep iconv_t */
#define VALUE2ICONV(v) ((iconv_t)((VALUE)(v) ^ -1))
#define ICONV2VALUE(c) ((VALUE)(c) ^ -1)
#ifndef HAVE_RB_BLOCK_GIVEN_P
#define rb_block_given_p() rb_iterator_p()
#endif
#ifdef HAVE_RB_OBJ_FREEZE
#define STRING_FREEZE rb_obj_freeze
#else
#define STRING_FREEZE rb_str_freeze
#endif
#ifdef HAVE_RB_STR_BUF_NEW
#define STRCAT(s, p, l) rb_str_buf_cat((s), (p), (l))
#define STRCAT2(s, p) rb_str_buf_cat2((s), (p))
#define STRAPPEND(s, p) rb_str_buf_append((s), (p))
#else
#define STRCAT(s, p, l) rb_str_cat((s), (p), (l))
#define STRCAT2(s, p) rb_str_cat2((s), (p))
#define STRAPPEND(s, p) rb_str_append((s), (p))
#endif
#ifndef StringValuePtr
#define StringValuePtr(v) STR2CSTR(v)
#endif
#ifndef OBJ_INFECT
#define OBJ_INFECT(x,s) (void)(FL_ABLE(x) && FL_ABLE(s) && (RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT))
#endif
struct iconv_env_t
{
iconv_t cd;
int argc;
VALUE *argv;
VALUE ret;
};
static VALUE rb_eIconvFailure;
static VALUE rb_eIconvIllegalSeq;
static VALUE rb_eIconvInvalidChar;
static VALUE rb_eIconvOutOfRange;
static ID rb_inserter;
static ID rb_success, rb_failed, rb_mesg;
static VALUE iconv_failure_initialize _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env));
static VALUE iconv_failure_success _((VALUE self));
static VALUE iconv_failure_failed _((VALUE self));
static VALUE iconv_finish _((VALUE self));
/*
=begin
= Classes & Modules
=end
*/
/*
=begin
== Iconv
=end
*/
static iconv_t
iconv_create
#ifdef HAVE_PROTOTYPES
(VALUE to, VALUE from)
#else /* HAVE_PROTOTYPES */
(to, from)
VALUE to;
VALUE from;
#endif /* HAVE_PROTOTYPES */
{
const char* tocode = StringValuePtr(to);
const char* fromcode = StringValuePtr(from);
iconv_t cd = iconv_open(tocode, fromcode);
if (cd == (iconv_t)-1) {
switch (errno) {
case EMFILE:
case ENFILE:
case ENOMEM:
rb_gc();
cd = iconv_open(tocode, fromcode);
}
if (cd == (iconv_t)-1) {
volatile VALUE msg = rb_str_new2("iconv(\"");
STRCAT2(STRAPPEND(msg, to), "\", \"");
STRCAT2(STRAPPEND(msg, from), "\")");
rb_sys_fail(StringValuePtr(msg));
}
}
return cd;
}
static VALUE
iconv_free
#ifdef HAVE_PROTOTYPES
(VALUE cd)
#else /* HAVE_PROTOTYPES */
(cd)
VALUE cd;
#endif /* HAVE_PROTOTYPES */
{
if (cd && iconv_close(VALUE2ICONV(cd)) == -1)
rb_sys_fail("iconv_close");
return Qnil;
}
#ifdef RUBY_DATA_FUNC
#define ICONV_FREE RUBY_DATA_FUNC(iconv_free)
#elif defined(HAVE_RUBY_DATA_FUNC)
#define ICONV_FREE (RUBY_DATA_FUNC)iconv_free
#else /* RUBY_DATA_FUNC: no way to know whether typedef'ed or not */
#define ICONV_FREE (void (*)_((void*)))iconv_free
#endif /* RUBY_DATA_FUNC */
static VALUE
iconv_try
#ifdef HAVE_PROTOTYPES
(iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen)
#else /* HAVE_PROTOTYPES */
(cd, inptr, inlen, outptr, outlen)
iconv_t cd;
const char **inptr;
size_t *inlen;
char **outptr;
size_t *outlen;
#endif /* HAVE_PROTOTYPES */
{
if (iconv(cd, (char **)inptr, inlen, outptr, outlen) == (size_t)-1) {
if (!*inlen)
return Qfalse;
switch (errno) {
case E2BIG:
/* try the left in next loop */
break;
case EILSEQ:
return rb_obj_alloc(rb_eIconvIllegalSeq);
case EINVAL:
return rb_obj_alloc(rb_eIconvInvalidChar);
default:
rb_sys_fail("iconv");
}
} else if (*inlen > 0) {
/* something goes wrong */
return rb_obj_alloc(rb_eIconvIllegalSeq);
}
return Qfalse;
}
#define iconv_fail(error, success, failed, env) \
rb_exc_raise(iconv_failure_initialize(error, success, failed, env))
static VALUE
iconv_failure_initialize
#ifdef HAVE_PROTOTYPES
(VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env)
#else /* HAVE_PROTOTYPES */
(error, success, failed, env)
VALUE error;
VALUE success;
VALUE failed;
struct iconv_env_t *env;
#endif /* HAVE_PROTOTYPES */
{
if (NIL_P(rb_ivar_get(error, rb_mesg)))
rb_ivar_set(error, rb_mesg, rb_inspect(failed));
if (env) {
success = rb_funcall3(env->ret, rb_inserter, 1, &success);
if (env->argc > 0) {
*(env->argv) = failed;
failed = rb_ary_new4(env->argc, env->argv);
}
}
rb_ivar_set(error, rb_success, success);
rb_ivar_set(error, rb_failed, failed);
return error;
}
static VALUE
rb_str_derive
#ifdef HAVE_PROTOTYPES
(VALUE str, const char* ptr, int len)
#else /* HAVE_PROTOTYPES */
(str, ptr, len)
VALUE str;
const char *ptr;
int len;
#endif /* HAVE_PROTOTYPES */
{
VALUE ret;
if (NIL_P(str))
return rb_str_new(ptr, len);
if (RSTRING(str)->ptr == ptr && RSTRING(str)->len == len)
return str;
ret = rb_str_new(ptr, len);
OBJ_INFECT(ret, str);
return ret;
}
static VALUE
iconv_convert
#ifdef HAVE_PROTOTYPES
(iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env)
#else /* HAVE_PROTOTYPES */
(cd, str, start, length, env)
iconv_t cd;
VALUE str;
int start;
int length;
struct iconv_env_t *env;
#endif /* HAVE_PROTOTYPES */
{
VALUE ret = Qfalse;
VALUE error = Qfalse;
const char *inptr, *instart;
size_t inlen;
/* I believe ONE CHARACTER never exceed this. */
char buffer[BUFSIZ];
char *outptr;
size_t outlen;
if (cd == (iconv_t)-1)
rb_raise(rb_eArgError, "closed iconv");
if (NIL_P(str)) {
/* Reset output pointer or something. */
inptr = "";
inlen = 0;
outptr = buffer;
outlen = sizeof(buffer);
error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
if (error)
iconv_fail(error, Qnil, Qnil, env);
inptr = NULL;
length = 0;
} else {
int slen;
Check_Type(str, T_STRING);
slen = RSTRING(str)->len;
inptr = RSTRING(str)->ptr;
if (start < 0 ? (start += slen) < 0 : start >= slen)
length = 0;
else if (length < 0 && (length += slen + 1) < 0)
length = 0;
else if ((length -= start) < 0)
length = 0;
else
inptr += start;
}
instart = inptr;
inlen = length;
do {
const char *tmpstart = inptr;
outptr = buffer;
outlen = sizeof(buffer);
error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
if (0 <= outlen && outlen <= sizeof(buffer)) {
outlen = sizeof(buffer) - outlen;
if (outlen > inptr - tmpstart || /* input can't contain output */
(outlen < inptr - tmpstart && inlen > 0) || /* something skipped */
memcmp(buffer, tmpstart, outlen)) /* something differs */
{
if (NIL_P(str)) {
ret = rb_str_new(buffer, outlen);
} else {
if (ret) {
ret = STRCAT(ret, instart, tmpstart - instart);
} else {
ret = rb_str_new(instart, tmpstart - instart);
OBJ_INFECT(ret, str);
}
ret = STRCAT(ret, buffer, outlen);
instart = inptr;
}
} else if (!inlen) {
inptr = tmpstart + outlen;
}
} else {
/* Some iconv() have a bug, return *outlen out of range */
char errmsg[50];
sprintf(errmsg, "bug?(output length = %d)", sizeof(buffer) - outlen);
error = rb_exc_new2(rb_eIconvOutOfRange, errmsg);
}
if (error) {
if (!ret)
ret = rb_str_derive(str, instart, inptr - instart);
str = rb_str_derive(str, inptr, inlen);
iconv_fail(error, ret, str, env);
}
} while (inlen > 0);
if (!ret)
ret = rb_str_derive(str, instart, inptr - instart);
return ret;
}
/*
=begin
=== Class methods
=end
*/
/*
=begin
--- Iconv.new(to, from)
Creates new code converter from a coding-system designated with ((|from|))
to another one designated with ((|to|)).
:Parameters
:((|to|))
coding-system name for destination.
:((|from|))
coding-system name for source.
:Exceptions
:(({TypeError}))
if ((|to|)) or ((|from|)) aren't String
:(({ArgumentError}))
if designated converter couldn't find out.
:(({SystemCallError}))
when (({iconv_open(3)})) failed.
--- Iconv.open(to, from)
Equivalents to ((<Iconv.new>)) except with in the case of called
with a block, yields with the new instance and closes it, and
returns the result which returned from the block.
=end
*/
static VALUE
iconv_s_new
#ifdef HAVE_PROTOTYPES
(int argc, VALUE *argv, VALUE klass)
#else /* HAVE_PROTOTYPES */
(argc, argv, klass)
int argc;
VALUE *argv;
VALUE klass;
#endif /* HAVE_PROTOTYPES */
{
VALUE obj = Data_Wrap_Struct(klass, 0, ICONV_FREE, 0);
rb_obj_call_init(obj, argc, argv);
return obj;
}
static VALUE
iconv_initialize
#ifdef HAVE_PROTOTYPES
(VALUE self, VALUE to, VALUE from)
#else /* HAVE_PROTOTYPES */
(self, to, from)
VALUE self;
VALUE to;
VALUE from;
#endif /* HAVE_PROTOTYPES */
{
iconv_free((VALUE)(DATA_PTR(self)));
DATA_PTR(self) = NULL;
DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from));
return self;
}
static VALUE
iconv_s_open
#ifdef HAVE_PROTOTYPES
(VALUE self, VALUE to, VALUE from)
#else /* HAVE_PROTOTYPES */
(self, to, from)
VALUE self;
VALUE to;
VALUE from;
#endif /* HAVE_PROTOTYPES */
{
VALUE cd = ICONV2VALUE(iconv_create(to, from));
if (rb_block_given_p()) {
self = Data_Wrap_Struct(self, NULL, NULL, (void *)cd);
return rb_ensure(rb_yield, self, (VALUE(*)())iconv_finish, self);
} else {
return Data_Wrap_Struct(self, NULL, ICONV_FREE, (void *)cd);
}
}
/*
=begin
--- Iconv.iconv(to, from, *strs)
Shorthand for
Iconv.new(to, from) {|cd| (strs + nil).collect {|s| cd.iconv(s)}}
:Parameters
:((|to|)), ((|from|))
see ((<Iconv.new>)).
:((|strs|))
strings to be converted.
:Exceptions
exceptions thrown by ((<Iconv.new>)) and ((<Iconv#iconv>)).
=end
*/
static VALUE
iconv_s_convert
#ifdef HAVE_PROTOTYPES
(struct iconv_env_t* env)
#else /* HAVE_PROTOTYPES */
(env)
struct iconv_env_t *env;
#endif /* HAVE_PROTOTYPES */
{
VALUE last = 0;
for (; env->argc > 0; --env->argc, ++env->argv) {
VALUE s = iconv_convert(env->cd, last = *(env->argv), 0, -1, env);
rb_funcall3(env->ret, rb_inserter, 1, &s);
}
if (!NIL_P(last)) {
VALUE s = iconv_convert(env->cd, Qnil, 0, 0, env);
if (RSTRING(s)->len)
rb_funcall3(env->ret, rb_inserter, 1, &s);
}
return env->ret;
}
static VALUE
iconv_s_iconv
#ifdef HAVE_PROTOTYPES
(int argc, VALUE *argv, VALUE self)
#else /* HAVE_PROTOTYPES */
(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
#endif /* HAVE_PROTOTYPES */
{
struct iconv_env_t arg;
if (argc < 2) /* needs `to' and `from' arguments at least */
rb_raise(rb_eArgError, "wrong # of arguments (%d for %d)", argc, 2);
arg.argc = argc -= 2;
arg.argv = argv + 2;
arg.ret = rb_ary_new2(argc);
arg.cd = iconv_create(argv[0], argv[1]);
return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
}
/*
=begin
=== Instance methods
=end
*/
/*
=begin
--- Iconv#close
Finishes conversion.
* After calling this, invoking method ((<Iconv#iconv>)) will cause
exception, but multiple calls of (({close})) are guaranteed to
end successfully.
* Returns a string contains the byte sequence to change the
output buffer to its initial shift state.
=end
*/
static VALUE
iconv_init_state
#ifdef HAVE_PROTOTYPES
(VALUE cd)
#else /* HAVE_PROTOTYPES */
(cd)
VALUE cd;
#endif /* HAVE_PROTOTYPES */
{
return iconv_convert(VALUE2ICONV(cd), Qnil, 0, 0, NULL);
}
static VALUE
iconv_finish
#ifdef HAVE_PROTOTYPES
(VALUE self)
#else /* HAVE_PROTOTYPES */
(self)
VALUE self;
#endif /* HAVE_PROTOTYPES */
{
VALUE cd;
Check_Type(self, T_DATA);
cd = (VALUE)DATA_PTR(self);
if (!cd) return Qnil;
DATA_PTR(self) = NULL;
return rb_ensure(iconv_init_state, cd, iconv_free, cd);
}
/*
=begin
--- Iconv#iconv(str, [ start = 0, [ length = -1 ] ])
Converts string and returns converted one.
* In the case of ((|str|)) is (({String})), converts (({str[start, length]})).
Returns converted string.
* In the case of ((|str|)) is (({nil})), places ((|converter|))
itself into initial shift state and just returns a string contains
the byte sequence to change the output buffer to its initial shift
state.
* Otherwise, causes exception.
:Parameters
:((|str|))
string to be converted or (({nil})).
:((|start|))
starting offset.
:((|length|))
conversion length,
(({nil})) or (({-1})) means whole string from (({start})).
:Exceptions
* ((<Iconv::IllegalSequence>))
* ((<Iconv::InvalidCharacter>))
* ((<Iconv::OutOfRange>))
=end
*/
static VALUE
iconv_iconv
#ifdef HAVE_PROTOTYPES
(int argc, VALUE *argv, VALUE self)
#else /* HAVE_PROTOTYPES */
(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
#endif /* HAVE_PROTOTYPES */
{
VALUE str, n1, n2;
Check_Type(self, T_DATA);
n1 = n2 = Qnil;
rb_scan_args(argc, argv, "12", &str, &n1, &n2);
return iconv_convert(VALUE2ICONV(DATA_PTR(self)), str,
NIL_P(n1) ? 0 : NUM2INT(n1),
NIL_P(n2) ? -1 : NUM2INT(n1),
NULL);
}
/*
=begin
= Exceptions
=end
*/
/*
=begin
== Iconv::Failure
Base exceptional attributes from ((<Iconv>)).
=== Instance methods
=end
*/
/*
=begin
--- Iconv::Failure#success
Returns string(s) translated successfully until the exception occurred.
* In the case of failure occurred within ((<Iconv.iconv>)), returned
value is an array of strings translated successfully preceding
failure and the last element is string on the way.
=end
*/
static VALUE
iconv_failure_success
#ifdef HAVE_PROTOTYPES
(VALUE self)
#else /* HAVE_PROTOTYPES */
(self)
VALUE self;
#endif /* HAVE_PROTOTYPES */
{
return rb_ivar_get(self, rb_success);
}
/*
=begin
--- Iconv::Failure#failed
Returns substring of the original string passed to ((<Iconv>)) that
starts at the character caused the exception.
=end
*/
static VALUE
iconv_failure_failed
#ifdef HAVE_PROTOTYPES
(VALUE self)
#else /* HAVE_PROTOTYPES */
(self)
VALUE self;
#endif /* HAVE_PROTOTYPES */
{
return rb_ivar_get(self, rb_failed);
}
/*
=begin
--- Iconv::Failure#inspect
Returns inspected string like as: #<(({type})): "(({success}))", "(({failed}))">
=end
*/
static VALUE
iconv_failure_inspect
#ifdef HAVE_PROTOTYPES
(VALUE self)
#else /* HAVE_PROTOTYPES */
(self)
VALUE self;
#endif /* HAVE_PROTOTYPES */
{
char *cname = rb_class2name(CLASS_OF(self));
VALUE success = iconv_failure_success(self);
VALUE failed = iconv_failure_failed(self);
VALUE str = STRCAT2(rb_str_new2("#<"), cname);
str = STRCAT(str, ": ", 2);
str = STRAPPEND(str, rb_inspect(success));
str = STRCAT(str, ", ", 2);
str = STRAPPEND(str, rb_inspect(failed));
return STRCAT(str, ">", 1);
}
/*
Hmmm, I don't like to write RD inside of function :-<.
=begin
== Iconv::IllegalSequence
Exception in the case of any illegal sequence detected.
=== Superclass
(({ArgumentError}))
=== Included Modules
((<Iconv::Failure>))
== Iconv::InvalidCharacter
Exception in the case of output coding system can't express the character.
=== Superclass
(({ArgumentError}))
=== Included Modules
((<Iconv::Failure>))
== Iconv::OutOfRange
Iconv library internal error. Must not occur.
=== Superclass
(({RuntimeError}))
=== Included Modules
((<Iconv::Failure>))
=end
*/
void
Init_iconv _((void))
{
VALUE rb_cIconv = rb_define_class("Iconv", rb_cData);
rb_define_singleton_method(rb_cIconv, "new", iconv_s_new, -1);
rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, 2);
rb_define_singleton_method(rb_cIconv, "iconv", iconv_s_iconv, -1);
rb_define_method(rb_cIconv, "initialize", iconv_initialize, 2);
rb_define_method(rb_cIconv, "close", iconv_finish, 0);
rb_define_method(rb_cIconv, "iconv", iconv_iconv, -1);
rb_define_const(rb_cIconv, "RCSID", STRING_FREEZE(rb_str_new2(rcsid)));
rb_eIconvFailure = rb_define_module_under(rb_cIconv, "Failure");
rb_define_method(rb_eIconvFailure, "success", iconv_failure_success, 0);
rb_define_method(rb_eIconvFailure, "failed", iconv_failure_failed, 0);
rb_define_method(rb_eIconvFailure, "inspect", iconv_failure_inspect, 0);
rb_eIconvIllegalSeq = rb_define_class_under(rb_cIconv, "IllegalSequence", rb_eArgError);
rb_eIconvInvalidChar = rb_define_class_under(rb_cIconv, "InvalidCharacter", rb_eArgError);
rb_eIconvOutOfRange = rb_define_class_under(rb_cIconv, "OutOfRange", rb_eRuntimeError);
rb_include_module(rb_eIconvIllegalSeq, rb_eIconvFailure);
rb_include_module(rb_eIconvInvalidChar, rb_eIconvFailure);
rb_include_module(rb_eIconvOutOfRange, rb_eIconvFailure);
rb_inserter = rb_intern("<<");
rb_success = rb_intern("success");
rb_failed = rb_intern("failed");
rb_mesg = rb_intern("mesg");
}
/*
=begin
== Example
(1) Instantiate a new ((<Iconv>)), use method ((<Iconv#iconv>)).
cd = Iconv.new(to, from)
begin
input.each {|s| output << cd.iconv(s)}
output << cd.iconv(nil) # don't forget this
ensure
cd.close
end
(2) Invoke ((<Iconv.new>)) with a block.
Iconv.new(to, from) do |cd|
input.each {|s| output << cd.iconv(s)}
output << cd.iconv(nil)
end
(3) Shorthand for (2).
Iconv.iconv(to, from, *input.to_a)
=end
*/
/*
=begin rlog
= $Log: iconv.c,v $
= Revision 0.4.5.0 2001/11/15 23:50:14 nobu
= * more 1.7 support.
= * bug fix of SEGV at exception. thanks to Masahiro Sakai.
=
= Revision 0.4.4.2 2001/11/13 05:17:51 nobu
= * use str_buf if available.
= * suppress a warning.
=
= Revision 0.4.4.1 2001/05/07 00:10:07 nobu
= * use StringValuePtr().
=
= Revision 0.4.4.0 2001/02/04 22:56:10 nobu
= 1.7 support
=
= Revision 0.4.3.2 2001/02/04 01:10:59 nobu
= * iconv_fail() became a macro, and setup in ((<iconv_failure_initialize>)).
=
= Revision 0.4.3.1 2000-10-14 10:21:06+09 nobu
= * Now ((<Iconv>)) inherits (({Data})) rather than (({Object})).
=
= Revision 0.4.3.0 2000-10-01 01:13:48+09 nobu
= * avoiding iconv()'s bug on some systems.
=
= Revision 0.4.2.4 2000-10-01 01:13:48+09 nobu
= * avoiding Solaris7&8 iconv()'s bug.
=
= Revision 0.4.2.3 2000-09-29 00:28:15+09 nobu
= * removed (({BUGGY_ICONV})) macro, always resets output pointer by
= converting an empty string before shift state initializations.
=
= Revision 0.4.2.2 2000-09-25 23:47:08+09 nobu
= * ignores errors when input length is 0.
=
= Revision 0.4.2.1 2000-09-25 06:24:54+09 nobu
= * trying to avoid problem of Free BSD iconv.
=
= Revision 0.4.2.0 2000-09-23 18:03:19+09 nobu
= * defaulted to none-buggy iconv.
=
= Revision 0.4.1.3 2000-08-15 06:46:48+09 nobu
= * declared ((<iconv_fail>)) with (({NORETURN})).
=
= Revision 0.4.1.2 2000-08-14 23:45:59+09 nobu
= * merged with unprotoized version.
=
= Revision 0.4.1.1 2000-08-13 13:17:38+09 nobu
= * ensures out of scope ((<Iconv>)) objects to be closed.
= * raises when closed ((<Iconv>)) passed to ((<Iconv#iconv>)).
= * (({RUBY_DATA_FUNC})) was not a macro.
=
= Revision 0.4.1.0 2000-07-08 07:15:02+09 nobu
= * compatible for 1.4 and 1.5.
=
= Revision 0.4.0.4 2000-07-08 07:15:02+09 nobu
= * defines (({OBJ_INFECT})) macro for 1.4.
=
= Revision 0.4.0.3 2000-07-08 07:03:47+09 nobu
= * uses (({rb_obj_freeze()})) if present.
=
= Revision 0.4.0.2 2000-07-08 06:49:02+09 nobu
= * now calls (({initialize})).
=
= Revision 0.4.0.1 2000-07-07 09:57:59+09 nobu
= * uses (({rb_block_given_p()})).
=
= Revision 0.4 2000-06-11 07:23:24+09 nobu
= * added license notice.
=
= Revision 0.3.3.0 2000-02-26 19:33:35+09 nobu
= Ruby style.
=
= Revision 0.3.2.3 2000-02-21 10:26:12+09 nobu
= Modified rd.
=
= Revision 0.3.2.2 2000-01-01 01:22:59+09 nobu
= * Strict check for change, whether output differs input.
= * Added (({rb_str_derive()})), to ensure infect with tainted object.
=
= Revision 0.3.2.1 1999-12-31 18:21:47+09 nobu
= * Initialize ((|@mesg|)) to failed.inspect and brushed up about
= exception.
=
= Revision 0.3.2.0 1999-12-15 19:19:15+09 nobu
= * Changed ((<Iconv::Failure>)) initialization.
=
= Revision 0.3.1.1 1999-12-10 14:40:01+09 nobu
= * Workaround for (({iconv()}))'s bug in glibc, by "resetting" with
= empty string before initializing output shift state.
=
= Revision 0.3.1.0 1999-12-09 19:15:34+09 nobu
= * Added NULL check for ((|outptr|)) before range check for
= ((|outlen|)). This may workaround some (({iconv()}))'s bug.
= * Shortened message upon ((<Iconv::OutOfRange>)).
=
= Revision 0.3 1999-12-06 18:51:36+09 nobu
= * Now (({iconv_convert})) no longer pushes returning value into array,
= except with exception. And uses (({<<})) to add ((|precedents|)),
= in other words, it's no longer bound to Array.
= * (({iconv_each})) also uses (({<<})).
= * ((<Iconv.iconv>)) no longer append surplus empty string.
=
= Revision 0.2.1.0 1999-12-06 16:33:53+09 nobu
= * Bug-fix of the workaround while converting UCS-4 string.
=
= Revision 0.2 1999-12-02 17:03:29+09 nobu
= * Workaround for (({iconv()}))'s bug returns horrible value as
= ((|outbytesleft|)).
= * Now ((<Iconv::Failure>)) is a module. So, the exceptions include it.
= * ((<Iconv::Failre#success>)) had been (({nil})).
= * (({iconv_convert()})) had returned original string.
=
= Revision 0.1 1999-12-01 20:28:09+09 nobu
= Release version
=
= Revision 0.0.2.0 1999-11-29 21:17:52+09 nobu
= * Changed Iconv#iconv's arguments order.
= * Now returns translation failure with exception.
=
= Revision 0.0.1.0 1999-11-21 12:27:48+09 nobu
= * Workaround for buggy iconv
= * Obsoleted iterator Iconv.iconv
= * Type check for String
= * Some bug-fix
=
= Revision 0.0.0.3 1999-11-18 16:24:11+09 nobu
= * Signature of iconv_s_iconv() had changed.
=
= Revision 0.0.0.2 1999-11-18 16:12:51+09 nobu
= * Now iconv_convert() accepts NULL for inlen.
= * Now Iconv.iconv can be called as iterator.
=
= Revision 0.0.0.1 1999-11-18 10:03:42+09 nobu
= * Taint new string when original one is tainted.
= * Added RCSID.
=
= Revision 0.0 1999-11-17 18:32:02+09 nobu
=end
*/
|