ext/iconv/iconv.c


DEFINITIONS

This source file includes following functions.
  1. _


   1  /* -*- mode:c; c-file-style:"ruby" -*- */
   2  /**********************************************************************
   3  
   4    iconv.c -
   5  
   6    $Author: matz $
   7    $Date: 2002/05/07 08:32:01 $
   8    created at: Wed Dec  1 20:28:09 JST 1999
   9  
  10    All the files in this distribution are covered under the Ruby's
  11    license (see the file COPYING).
  12  
  13  **********************************************************************/
  14  
  15  /*
  16  =begin
  17  = Summary
  18  Ruby extension for codeset conversion.
  19  
  20  = Abstract
  21  Iconv is a wrapper class for UNIX 95 (({iconv()})) function family, which
  22  translates string between various coding systems.
  23  
  24  See ((<Open Group|URL:http://www.opengroup.org/>))'s on-line documents for more details.
  25  * ((<iconv.h|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.h.html>))
  26  * ((<iconv_open()|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_open.html>))
  27  * ((<iconv()|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.html>))
  28  * ((<iconv_close()|URL:http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_close.html>))
  29  
  30  Which coding systems are available, it depends on the platform.
  31  
  32  =end
  33  */
  34  
  35  #include <errno.h>
  36  #include <iconv.h>
  37  #include <assert.h>
  38  #include "ruby.h"
  39  #include "intern.h"
  40  
  41  /* Invalid value for iconv_t is -1 but 0 for VALUE, I hope VALUE is
  42     big enough to keep iconv_t */
  43  #define VALUE2ICONV(v) ((iconv_t)((VALUE)(v) ^ -1))
  44  #define ICONV2VALUE(c) ((VALUE)(c) ^ -1)
  45  
  46  struct iconv_env_t
  47  {
  48      iconv_t cd;
  49      int argc;
  50      VALUE *argv;
  51      VALUE ret;
  52  };
  53  
  54  static VALUE rb_eIconvFailure;
  55  static VALUE rb_eIconvIllegalSeq;
  56  static VALUE rb_eIconvInvalidChar;
  57  static VALUE rb_eIconvOutOfRange;
  58  static ID rb_inserter;
  59  
  60  static ID rb_success, rb_failed, rb_mesg;
  61  static VALUE iconv_failure_initialize _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env));
  62  static VALUE iconv_failure_success _((VALUE self));
  63  static VALUE iconv_failure_failed _((VALUE self));
  64  
  65  static iconv_t iconv_create _((VALUE to, VALUE from));
  66  static VALUE iconv_free _((VALUE cd));
  67  static VALUE iconv_try _((iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen));
  68  static VALUE rb_str_derive _((VALUE str, const char* ptr, int len));
  69  static VALUE iconv_convert _((iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env));
  70  static VALUE iconv_s_allocate _((VALUE klass));
  71  static VALUE iconv_initialize _((VALUE self, VALUE to, VALUE from));
  72  static VALUE iconv_s_open _((VALUE self, VALUE to, VALUE from));
  73  static VALUE iconv_s_convert _((struct iconv_env_t* env));
  74  static VALUE iconv_s_iconv _((int argc, VALUE *argv, VALUE self));
  75  static VALUE iconv_init_state _((VALUE cd));
  76  static VALUE iconv_finish _((VALUE self));
  77  static VALUE iconv_iconv _((int argc, VALUE *argv, VALUE self));
  78  
  79  
  80  /*
  81  =begin
  82  = Classes & Modules
  83  =end
  84  */
  85  
  86  /*
  87  =begin
  88  == Iconv
  89  =end
  90  */
  91  static iconv_t
  92  iconv_create
  93  #ifdef HAVE_PROTOTYPES
  94  (VALUE to, VALUE from)
  95  #else /* HAVE_PROTOTYPES */
  96      (to, from)
  97      VALUE to;
  98      VALUE from;
  99  #endif /* HAVE_PROTOTYPES */
 100  {
 101      const char* tocode = StringValuePtr(to);
 102      const char* fromcode = StringValuePtr(from);
 103  
 104      iconv_t cd = iconv_open(tocode, fromcode);
 105  
 106      if (cd == (iconv_t)-1) {
 107          switch (errno) {
 108            case EMFILE:
 109            case ENFILE:
 110            case ENOMEM:
 111              rb_gc();
 112              cd = iconv_open(tocode, fromcode);
 113          }
 114          if (cd == (iconv_t)-1) {
 115              volatile VALUE msg = rb_str_new2("iconv(\"");
 116              rb_str_buf_cat2(rb_str_buf_append(msg, to), "\", \"");
 117              rb_str_buf_cat2(rb_str_buf_append(msg, from), "\")");
 118              rb_sys_fail(StringValuePtr(msg));
 119          }
 120      }
 121  
 122      return cd;
 123  }
 124  
 125  static VALUE
 126  iconv_free
 127  #ifdef HAVE_PROTOTYPES
 128  (VALUE cd)
 129  #else /* HAVE_PROTOTYPES */
 130      (cd)
 131      VALUE cd;
 132  #endif /* HAVE_PROTOTYPES */
 133  {
 134      if (cd && iconv_close(VALUE2ICONV(cd)) == -1)
 135          rb_sys_fail("iconv_close");
 136      return Qnil;
 137  }
 138  
 139  #define ICONV_FREE (RUBY_DATA_FUNC)iconv_free
 140  
 141  static VALUE
 142  iconv_try
 143  #ifdef HAVE_PROTOTYPES
 144  (iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen)
 145  #else /* HAVE_PROTOTYPES */
 146      (cd, inptr, inlen, outptr, outlen)
 147      iconv_t cd;
 148      const char **inptr;
 149      size_t *inlen;
 150      char **outptr;
 151      size_t *outlen;
 152  #endif /* HAVE_PROTOTYPES */
 153  {
 154      if (iconv(cd, (char **)inptr, inlen, outptr, outlen) == (size_t)-1) {
 155          if (!*inlen)
 156              return Qfalse;
 157          switch (errno) {
 158            case E2BIG:
 159              /* try the left in next loop */
 160              break;
 161            case EILSEQ:
 162              return rb_class_new_instance(0, 0, rb_eIconvIllegalSeq);
 163            case EINVAL:
 164              return rb_class_new_instance(0, 0, rb_eIconvInvalidChar);
 165            default:
 166              rb_sys_fail("iconv");
 167          }
 168      }
 169      else if (*inlen > 0) {
 170          /* something goes wrong */
 171          return rb_class_new_instance(0, 0, rb_eIconvIllegalSeq);
 172      }
 173      return Qfalse;
 174  }
 175  
 176  #define iconv_fail(error, success, failed, env) \
 177          rb_exc_raise(iconv_failure_initialize(error, success, failed, env))
 178  
 179  static VALUE
 180  iconv_failure_initialize
 181  #ifdef HAVE_PROTOTYPES
 182  (VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env)
 183  #else /* HAVE_PROTOTYPES */
 184      (error, success, failed, env)
 185      VALUE error;
 186      VALUE success;
 187      VALUE failed;
 188      struct iconv_env_t *env;
 189  #endif /* HAVE_PROTOTYPES */
 190  {
 191      if (!rb_ivar_defined(error, rb_mesg) || NIL_P(rb_ivar_get(error, rb_mesg)))
 192          rb_ivar_set(error, rb_mesg, rb_inspect(failed));
 193      if (env) {
 194          success = rb_funcall3(env->ret, rb_inserter, 1, &success);
 195          if (env->argc > 0) {
 196              *(env->argv) = failed;
 197              failed = rb_ary_new4(env->argc, env->argv);
 198          }
 199      }
 200      rb_ivar_set(error, rb_success, success);
 201      rb_ivar_set(error, rb_failed, failed);
 202      return error;
 203  }
 204  
 205  static VALUE
 206  rb_str_derive
 207  #ifdef HAVE_PROTOTYPES
 208  (VALUE str, const char* ptr, int len)
 209  #else /* HAVE_PROTOTYPES */
 210      (str, ptr, len)
 211      VALUE str;
 212      const char *ptr;
 213      int len;
 214  #endif /* HAVE_PROTOTYPES */
 215  {
 216      VALUE ret;
 217  
 218      if (NIL_P(str))
 219          return rb_str_new(ptr, len);
 220      if (RSTRING(str)->ptr == ptr && RSTRING(str)->len == len)
 221          return str;
 222      ret = rb_str_new(ptr, len);
 223      OBJ_INFECT(ret, str);
 224      return ret;
 225  }
 226  
 227  static VALUE
 228  iconv_convert
 229  #ifdef HAVE_PROTOTYPES
 230  (iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env)
 231  #else /* HAVE_PROTOTYPES */
 232      (cd, str, start, length, env)
 233      iconv_t cd;
 234      VALUE str;
 235      int start;
 236      int length;
 237      struct iconv_env_t *env;
 238  #endif /* HAVE_PROTOTYPES */
 239  {
 240      VALUE ret = Qfalse;
 241      VALUE error = Qfalse;
 242      const char *inptr, *instart;
 243      size_t inlen;
 244      /* I believe ONE CHARACTER never exceed this. */
 245      char buffer[BUFSIZ];
 246      char *outptr;
 247      size_t outlen;
 248  
 249      if (cd == (iconv_t)-1)
 250          rb_raise(rb_eArgError, "closed iconv");
 251  
 252      if (NIL_P(str)) {
 253          /* Reset output pointer or something. */
 254          inptr = "";
 255          inlen = 0;
 256          outptr = buffer;
 257          outlen = sizeof(buffer);
 258          error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
 259          if (error)
 260              iconv_fail(error, Qnil, Qnil, env);
 261  
 262          inptr = NULL;
 263          length = 0;
 264      }
 265      else {
 266          int slen;
 267  
 268          Check_Type(str, T_STRING);
 269          slen = RSTRING(str)->len;
 270          inptr = RSTRING(str)->ptr;
 271  
 272          if (start < 0 ? (start += slen) < 0 : start >= slen)
 273              length = 0;
 274          else if (length < 0 && (length += slen + 1) < 0)
 275              length = 0;
 276          else if ((length -= start) < 0)
 277              length = 0;
 278          else
 279              inptr += start;
 280      }
 281      instart = inptr;
 282      inlen = length;
 283  
 284      do {
 285          const char *tmpstart = inptr;
 286          outptr = buffer;
 287          outlen = sizeof(buffer);
 288  
 289          error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
 290  
 291          if (0 <= outlen && outlen <= sizeof(buffer)) {
 292              outlen = sizeof(buffer) - outlen;
 293              if (outlen > inptr - tmpstart || /* input can't contain output */
 294                  (outlen < inptr - tmpstart && inlen > 0) || /* something skipped */
 295                  memcmp(buffer, tmpstart, outlen)) /* something differs */
 296              {
 297                  if (NIL_P(str)) {
 298                      ret = rb_str_new(buffer, outlen);
 299                  }
 300                  else {
 301                      if (ret) {
 302                          ret = rb_str_buf_cat(ret, instart, tmpstart - instart);
 303                      }
 304                      else {
 305                          ret = rb_str_new(instart, tmpstart - instart);
 306                          OBJ_INFECT(ret, str);
 307                      }
 308                      ret = rb_str_buf_cat(ret, buffer, outlen);
 309                      instart = inptr;
 310                  }
 311              }
 312              else if (!inlen) {
 313                  inptr = tmpstart + outlen;
 314              }
 315          }
 316          else {
 317              /* Some iconv() have a bug, return *outlen out of range */
 318              char errmsg[50];
 319              sprintf(errmsg, "bug?(output length = %d)", sizeof(buffer) - outlen);
 320              error = rb_exc_new2(rb_eIconvOutOfRange, errmsg);
 321          }
 322  
 323          if (error) {
 324              if (!ret)
 325                  ret = rb_str_derive(str, instart, inptr - instart);
 326              str = rb_str_derive(str, inptr, inlen);
 327              iconv_fail(error, ret, str, env);
 328          }
 329      } while (inlen > 0);
 330  
 331      if (!ret)
 332          ret = rb_str_derive(str, instart, inptr - instart);
 333      return ret;
 334  }
 335  
 336  
 337  /*
 338  =begin
 339  === Class methods
 340  =end
 341  */
 342  /*
 343  =begin
 344  --- Iconv.new(to, from) {|cd| ...}
 345      Creates new code converter from a coding-system designated with ((|from|))
 346      to another one designated with ((|to|)).
 347      :Parameters
 348        :((|to|))
 349          coding-system name for destination.
 350        :((|from|))
 351          coding-system name for source.
 352      :Exceptions
 353        :(({TypeError}))
 354          if ((|to|)) or ((|from|)) aren't String
 355        :(({ArgumentError}))
 356          if designated converter couldn't find out.
 357        :(({SystemCallError}))
 358          when (({iconv_open(3)})) failed.
 359  
 360  --- Iconv.open(to, from)
 361      Equivalents to ((<Iconv.new>)) except with in the case of called
 362      with a block, yields with the new instance and closes it, and
 363      returns the result which returned from the block.
 364  =end
 365  */
 366  static VALUE
 367  iconv_s_allocate
 368  #ifdef HAVE_PROTOTYPES
 369  (VALUE klass)
 370  #else /* HAVE_PROTOTYPES */
 371      (klass)
 372      VALUE klass;
 373  #endif /* HAVE_PROTOTYPES */
 374  {
 375      return Data_Wrap_Struct(klass, 0, ICONV_FREE, 0);
 376  }
 377  
 378  static VALUE
 379  iconv_initialize
 380  #ifdef HAVE_PROTOTYPES
 381  (VALUE self, VALUE to, VALUE from)
 382  #else /* HAVE_PROTOTYPES */
 383      (self, to, from)
 384      VALUE self;
 385      VALUE to;
 386      VALUE from;
 387  #endif /* HAVE_PROTOTYPES */
 388  {
 389      iconv_free((VALUE)(DATA_PTR(self)));
 390      DATA_PTR(self) = NULL;
 391      DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from));
 392      return self;
 393  }
 394  
 395  static VALUE
 396  iconv_s_open
 397  #ifdef HAVE_PROTOTYPES
 398  (VALUE self, VALUE to, VALUE from)
 399  #else /* HAVE_PROTOTYPES */
 400      (self, to, from)
 401      VALUE self;
 402      VALUE to;
 403      VALUE from;
 404  #endif /* HAVE_PROTOTYPES */
 405  {
 406      VALUE cd = ICONV2VALUE(iconv_create(to, from));
 407  
 408      if (rb_block_given_p()) {
 409          self = Data_Wrap_Struct(self, NULL, NULL, (void *)cd);
 410          return rb_ensure(rb_yield, self, (VALUE(*)())iconv_finish, self);
 411      }
 412      else {
 413          return Data_Wrap_Struct(self, NULL, ICONV_FREE, (void *)cd);
 414      }
 415  }
 416  
 417  /*
 418  =begin
 419  --- Iconv.iconv(to, from, *strs)
 420      Shorthand for
 421        Iconv.open(to, from) {|cd| (strs + [nil]).collect {|s| cd.iconv(s)}}
 422      :Parameters
 423        :((|to|)), ((|from|))
 424          see ((<Iconv.new>)).
 425        :((|strs|))
 426          strings to be converted.
 427      :Exceptions
 428        exceptions thrown by ((<Iconv.new>)), ((<Iconv.open>)) and
 429        ((<Iconv#iconv>)).
 430  =end
 431  */
 432  
 433  static VALUE
 434  iconv_s_convert
 435  #ifdef HAVE_PROTOTYPES
 436  (struct iconv_env_t* env)
 437  #else /* HAVE_PROTOTYPES */
 438      (env)
 439      struct iconv_env_t *env;
 440  #endif /* HAVE_PROTOTYPES */
 441  {
 442      VALUE last = 0;
 443  
 444      for (; env->argc > 0; --env->argc, ++env->argv) {
 445          VALUE s = iconv_convert(env->cd, last = *(env->argv), 0, -1, env);
 446          rb_funcall3(env->ret, rb_inserter, 1, &s);
 447      }
 448  
 449      if (!NIL_P(last)) {
 450          VALUE s = iconv_convert(env->cd, Qnil, 0, 0, env);
 451          if (RSTRING(s)->len)
 452              rb_funcall3(env->ret, rb_inserter, 1, &s);
 453      }
 454  
 455      return env->ret;
 456  }
 457  
 458  static VALUE
 459  iconv_s_iconv
 460  #ifdef HAVE_PROTOTYPES
 461  (int argc, VALUE *argv, VALUE self)
 462  #else /* HAVE_PROTOTYPES */
 463      (argc, argv, self)
 464      int argc;
 465      VALUE *argv;
 466      VALUE self;
 467  #endif /* HAVE_PROTOTYPES */
 468  {
 469      struct iconv_env_t arg;
 470  
 471      if (argc < 2)               /* needs `to' and `from' arguments at least */
 472          rb_raise(rb_eArgError, "wrong # of arguments (%d for %d)", argc, 2);
 473  
 474      arg.argc = argc -= 2;
 475      arg.argv = argv + 2;
 476      arg.ret = rb_ary_new2(argc);
 477      arg.cd = iconv_create(argv[0], argv[1]);
 478      return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
 479  }
 480  
 481  
 482  /*
 483  =begin
 484  === Instance methods
 485  =end
 486  */
 487  /*
 488  =begin
 489  --- Iconv#close
 490      Finishes conversion.
 491      * After calling this, invoking method ((<Iconv#iconv>)) will cause
 492        exception, but multiple calls of (({close})) are guaranteed to
 493        end successfully.
 494      * Returns a string contains the byte sequence to change the
 495        output buffer to its initial shift state.
 496  =end
 497  */
 498  static VALUE
 499  iconv_init_state
 500  #ifdef HAVE_PROTOTYPES
 501  (VALUE cd)
 502  #else /* HAVE_PROTOTYPES */
 503      (cd)
 504      VALUE cd;
 505  #endif /* HAVE_PROTOTYPES */
 506  {
 507      return iconv_convert(VALUE2ICONV(cd), Qnil, 0, 0, NULL);
 508  }
 509  
 510  static VALUE
 511  iconv_finish
 512  #ifdef HAVE_PROTOTYPES
 513  (VALUE self)
 514  #else /* HAVE_PROTOTYPES */
 515      (self)
 516      VALUE self;
 517  #endif /* HAVE_PROTOTYPES */
 518  {
 519      VALUE cd;
 520  
 521      Check_Type(self, T_DATA);
 522  
 523      cd = (VALUE)DATA_PTR(self);
 524      if (!cd) return Qnil;
 525      DATA_PTR(self) = NULL;
 526  
 527      return rb_ensure(iconv_init_state, cd, iconv_free, cd);
 528  }
 529  
 530  /*
 531  =begin
 532  --- Iconv#iconv(str, [ start = 0, [ length = -1 ] ])
 533      Converts string and returns converted one.
 534      * In the case of ((|str|)) is (({String})), converts (({str[start, length]})).
 535        Returns converted string.
 536      * In the case of ((|str|)) is (({nil})), places ((|converter|))
 537        itself into initial shift state and just returns a string contains
 538        the byte sequence to change the output buffer to its initial shift
 539        state.
 540      * Otherwise, causes exception.
 541      :Parameters
 542        :((|str|))
 543          string to be converted or (({nil})).
 544        :((|start|))
 545          starting offset.
 546        :((|length|))
 547          conversion length,
 548          (({nil})) or (({-1})) means whole string from (({start})).
 549      :Exceptions
 550        * ((<Iconv::IllegalSequence>))
 551        * ((<Iconv::InvalidCharacter>))
 552        * ((<Iconv::OutOfRange>))
 553  =end
 554  */
 555  static VALUE
 556  iconv_iconv
 557  #ifdef HAVE_PROTOTYPES
 558  (int argc, VALUE *argv, VALUE self)
 559  #else /* HAVE_PROTOTYPES */
 560      (argc, argv, self)
 561      int argc;
 562      VALUE *argv;
 563      VALUE self;
 564  #endif /* HAVE_PROTOTYPES */
 565  {
 566      VALUE str, n1, n2;
 567  
 568      Check_Type(self, T_DATA);
 569  
 570      n1 = n2 = Qnil;
 571      rb_scan_args(argc, argv, "12", &str, &n1, &n2);
 572  
 573      return iconv_convert(VALUE2ICONV(DATA_PTR(self)), str,
 574                           NIL_P(n1) ? 0 : NUM2INT(n1),
 575                           NIL_P(n2) ? -1 : NUM2INT(n1),
 576                           NULL);
 577  }
 578  
 579  
 580  /*
 581  =begin
 582  = Exceptions
 583  =end
 584  */
 585  /*
 586  =begin
 587  == Iconv::Failure
 588  Base exceptional attributes from ((<Iconv>)).
 589  
 590  === Instance methods
 591  =end
 592  */
 593  /*
 594  =begin
 595  --- Iconv::Failure#success
 596      Returns string(s) translated successfully until the exception occurred.
 597      * In the case of failure occurred within ((<Iconv.iconv>)), returned
 598        value is an array of strings translated successfully preceding
 599        failure and the last element is string on the way.
 600  =end
 601  */
 602  static VALUE
 603  iconv_failure_success
 604  #ifdef HAVE_PROTOTYPES
 605  (VALUE self)
 606  #else /* HAVE_PROTOTYPES */
 607      (self)
 608      VALUE self;
 609  #endif /* HAVE_PROTOTYPES */
 610  {
 611      return rb_ivar_get(self, rb_success);
 612  }
 613  
 614  /*
 615  =begin
 616  --- Iconv::Failure#failed
 617      Returns substring of the original string passed to ((<Iconv>)) that
 618      starts at the character caused the exception. 
 619  =end
 620  */
 621  static VALUE
 622  iconv_failure_failed
 623  #ifdef HAVE_PROTOTYPES
 624  (VALUE self)
 625  #else /* HAVE_PROTOTYPES */
 626      (self)
 627      VALUE self;
 628  #endif /* HAVE_PROTOTYPES */
 629  {
 630      return rb_ivar_get(self, rb_failed);
 631  }
 632  
 633  /*
 634  =begin
 635  --- Iconv::Failure#inspect
 636      Returns inspected string like as: #<(({type})): "(({success}))", "(({failed}))">
 637  =end
 638  */
 639  static VALUE
 640  iconv_failure_inspect
 641  #ifdef HAVE_PROTOTYPES
 642  (VALUE self)
 643  #else /* HAVE_PROTOTYPES */
 644      (self)
 645      VALUE self;
 646  #endif /* HAVE_PROTOTYPES */
 647  {
 648      char *cname = rb_class2name(CLASS_OF(self));
 649      VALUE success = iconv_failure_success(self);
 650      VALUE failed = iconv_failure_failed(self);
 651      VALUE str = rb_str_buf_cat2(rb_str_new2("#<"), cname);
 652      str = rb_str_buf_cat(str, ": ", 2);
 653      str = rb_str_buf_append(str, rb_inspect(success));
 654      str = rb_str_buf_cat(str, ", ", 2);
 655      str = rb_str_buf_append(str, rb_inspect(failed));
 656      return rb_str_buf_cat(str, ">", 1);
 657  }
 658  
 659  /*
 660    Hmmm, I don't like to write RD inside of function :-<.
 661  
 662  =begin
 663  == Iconv::IllegalSequence
 664  Input conversion stopped due to an input byte that does not belong to
 665  the input codeset, or the output codeset does not contain the
 666  character.
 667  === Superclass
 668  (({ArgumentError}))
 669  === Included Modules
 670  ((<Iconv::Failure>))
 671  
 672  == Iconv::InvalidCharacter
 673  Input conversion stopped due to an incomplete character or shift
 674  sequence at the end of the input buffer.
 675  === Superclass
 676  (({ArgumentError}))
 677  === Included Modules
 678  ((<Iconv::Failure>))
 679  
 680  == Iconv::OutOfRange
 681  Iconv library internal error.  Must not occur.
 682  === Superclass
 683  (({RuntimeError}))
 684  === Included Modules
 685  ((<Iconv::Failure>))
 686  =end
 687  */
 688  
 689  void
 690  Init_iconv _((void))
 691  {
 692      VALUE rb_cIconv = rb_define_class("Iconv", rb_cData);
 693      rb_define_singleton_method(rb_cIconv, "allocate", iconv_s_allocate, 0);
 694      rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, 2);
 695      rb_define_singleton_method(rb_cIconv, "iconv", iconv_s_iconv, -1);
 696      rb_define_method(rb_cIconv, "initialize", iconv_initialize, 2);
 697      rb_define_method(rb_cIconv, "close", iconv_finish, 0);
 698      rb_define_method(rb_cIconv, "iconv", iconv_iconv, -1);
 699  
 700      rb_eIconvFailure = rb_define_module_under(rb_cIconv, "Failure");
 701      rb_define_method(rb_eIconvFailure, "success", iconv_failure_success, 0);
 702      rb_define_method(rb_eIconvFailure, "failed", iconv_failure_failed, 0);
 703      rb_define_method(rb_eIconvFailure, "inspect", iconv_failure_inspect, 0);
 704  
 705      rb_eIconvIllegalSeq = rb_define_class_under(rb_cIconv, "IllegalSequence", rb_eArgError);
 706      rb_eIconvInvalidChar = rb_define_class_under(rb_cIconv, "InvalidCharacter", rb_eArgError);
 707      rb_eIconvOutOfRange = rb_define_class_under(rb_cIconv, "OutOfRange", rb_eRuntimeError);
 708      rb_include_module(rb_eIconvIllegalSeq, rb_eIconvFailure);
 709      rb_include_module(rb_eIconvInvalidChar, rb_eIconvFailure);
 710      rb_include_module(rb_eIconvOutOfRange, rb_eIconvFailure);
 711  
 712      rb_inserter = rb_intern("<<");
 713      rb_success = rb_intern("success");
 714      rb_failed = rb_intern("failed");
 715      rb_mesg = rb_intern("mesg");
 716  }
 717  
 718  
 719  /*
 720  =begin
 721  == Example
 722  (1) Instantiate a new ((<Iconv>)), use method ((<Iconv#iconv>)).
 723        cd = Iconv.new(to, from)
 724        begin
 725          input.each {|s| output << cd.iconv(s)}
 726          output << cd.iconv(nil)      # don't forget this
 727        ensure
 728          cd.close
 729        end
 730  (2) Invoke ((<Iconv.open>)) with a block.
 731        Iconv.open(to, from) do |cd|
 732          input.each {|s| output << cd.iconv(s)}
 733          output << cd.iconv(nil)
 734        end
 735  (3) Shorthand for (2).
 736        Iconv.iconv(to, from, *input.to_a)
 737  =end
 738  */