This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate mainline
[perl5.git] / ext / Encode / Encode.xs
index 3bdc3f7..992fbfe 100644 (file)
+/*
+ $Id: Encode.xs,v 1.31 2002/04/20 23:43:47 dankogai Exp dankogai $
+ */
+
+#define PERL_NO_GET_CONTEXT
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+#define U8 U8
+#include "encode.h"
+
+/* set 1 or more to profile.  t/encoding.t dumps core because of
+   Perl_warner and PerlIO don't work well */
+#define ENCODE_XS_PROFILE 0
 
-#define UNIMPLEMENTED(x,y) y x (SV *sv, char *encoding) {   \
+/* set 0 to disable floating point to calculate buffer size for
+   encode_method().  1 is recommended. 2 restores NI-S original */
+#define ENCODE_XS_USEFP   1
+
+#define UNIMPLEMENTED(x,y) y x (SV *sv, char *encoding) {dTHX;   \
                          Perl_croak(aTHX_ "panic_unimplemented"); \
                         return (y)0; /* fool picky compilers */ \
                          }
-UNIMPLEMENTED(_encoded_utf8_to_bytes, I32)
-UNIMPLEMENTED(_encoded_bytes_to_utf8, I32)
-
-#ifdef USE_PERLIO
-#include "perliol.h"
+/**/
+UNIMPLEMENTED(_encoded_utf8_to_bytes, I32);
+UNIMPLEMENTED(_encoded_bytes_to_utf8, I32);
 
-typedef struct
+void
+Encode_XSEncoding(pTHX_ encode_t * enc)
 {
- PerlIOBuf     base;         /* PerlIOBuf stuff */
- SV *          bufsv;
- SV *          enc;
-} PerlIOEncode;
-
-
-IV
-PerlIOEncode_pushed(PerlIO *f, const char *mode,const char *arg,STRLEN len)
-{
- PerlIOEncode *e = PerlIOSelf(f,PerlIOEncode);
- dTHX;
- dSP;
- IV code;
- code = PerlIOBuf_pushed(f,mode,Nullch,0);
- ENTER;
- SAVETMPS;
- PUSHMARK(sp);
- XPUSHs(sv_2mortal(newSVpv("Encode",0)));
- XPUSHs(sv_2mortal(newSVpvn(arg,len)));
- PUTBACK;
- if (perl_call_method("getEncoding",G_SCALAR) != 1)
-  return -1;
- SPAGAIN;
- e->enc = POPs;
- PUTBACK;
- if (!SvROK(e->enc))
-  return -1;
- SvREFCNT_inc(e->enc);
- FREETMPS;
- LEAVE;
- PerlIOBase(f)->flags |= PERLIO_F_UTF8;
- return code;
+    dSP;
+    HV *stash = gv_stashpv("Encode::XS", TRUE);
+    SV *sv = sv_bless(newRV_noinc(newSViv(PTR2IV(enc))), stash);
+    int i = 0;
+    PUSHMARK(sp);
+    XPUSHs(sv);
+    while (enc->name[i]) {
+       const char *name = enc->name[i++];
+       XPUSHs(sv_2mortal(newSVpvn(name, strlen(name))));
+    }
+    PUTBACK;
+    call_pv("Encode::define_encoding", G_DISCARD);
+    SvREFCNT_dec(sv);
 }
 
-IV
-PerlIOEncode_popped(PerlIO *f)
+void
+call_failure(SV * routine, U8 * done, U8 * dest, U8 * orig)
 {
- PerlIOEncode *e = PerlIOSelf(f,PerlIOEncode);
- dTHX;
- if (e->enc)
-  {
-   SvREFCNT_dec(e->enc);
-   e->enc = Nullsv;
-  }
- if (e->bufsv)
-  {
-   SvREFCNT_dec(e->bufsv);
-   e->bufsv = Nullsv;
-  }
- return 0;
+    /* Exists for breakpointing */
 }
 
-STDCHAR *
-PerlIOEncode_get_base(PerlIO *f)
-{
- PerlIOEncode *e = PerlIOSelf(f,PerlIOEncode);
- dTHX;
- if (!e->base.bufsiz)
-  e->base.bufsiz = 1024;
- if (!e->bufsv)
-  {
-   e->bufsv = newSV(e->base.bufsiz);
-   sv_setpvn(e->bufsv,"",0);
-  }
- e->base.buf = SvPVX(e->bufsv);
- if (!e->base.ptr)
-  e->base.ptr = e->base.buf;
- if (!e->base.end)
-  e->base.end = e->base.buf;
- if (e->base.ptr < e->base.buf || e->base.ptr > e->base.buf+SvLEN(e->bufsv))
-  {
-   Perl_warn(aTHX_ " ptr %p(%p)%p",
-             e->base.buf,e->base.ptr,e->base.buf+SvLEN(e->bufsv));
-   abort();
-  }
- if (SvLEN(e->bufsv) < e->base.bufsiz)
-  {
-   SSize_t poff = e->base.ptr - e->base.buf;
-   SSize_t eoff = e->base.end - e->base.buf;
-   e->base.buf  = SvGROW(e->bufsv,e->base.bufsiz);
-   e->base.ptr  = e->base.buf + poff;
-   e->base.end  = e->base.buf + eoff;
-  }
- if (e->base.ptr < e->base.buf || e->base.ptr > e->base.buf+SvLEN(e->bufsv))
-  {
-   Perl_warn(aTHX_ " ptr %p(%p)%p",
-             e->base.buf,e->base.ptr,e->base.buf+SvLEN(e->bufsv));
-   abort();
-  }
- return e->base.buf;
-}
 
-static void
-Break(void)
+static SV *
+encode_method(pTHX_ encode_t * enc, encpage_t * dir, SV * src,
+             int check)
 {
+    STRLEN slen;
+    U8 *s = (U8 *) SvPV(src, slen);
+    STRLEN tlen  = slen;
+    STRLEN ddone = 0;
+    STRLEN sdone = 0;
+
+    /* We allocate slen+1.
+       PerlIO dumps core if this value is smaller than this. */
+    SV *dst = sv_2mortal(newSV(slen+1));
+    U8 *d = (U8 *)SvPVX(dst);
+    STRLEN dlen = SvLEN(dst)-1;
+    int code;
+
+    if (!slen){
+       SvCUR_set(dst, 0);
+       SvPOK_only(dst);
+       goto ENCODE_END;
+    }
+
+    while (code = do_encode(dir, s, &slen, d, dlen, &dlen, !check))
+    {
+       SvCUR_set(dst, dlen+ddone);
+       SvPOK_only(dst);
+       
+       if (code == ENCODE_FALLBACK || code == ENCODE_PARTIAL){
+           break;
+       }
+       switch (code) {
+       case ENCODE_NOSPACE:
+       {       
+           STRLEN more = 0; /* make sure you initialize! */
+           STRLEN sleft;
+           sdone += slen;
+           ddone += dlen;
+           sleft = tlen - sdone;
+#if ENCODE_XS_PROFILE >= 2
+           Perl_warn(aTHX_
+                     "more=%d, sdone=%d, sleft=%d, SvLEN(dst)=%d\n",
+                     more, sdone, sleft, SvLEN(dst));
+#endif
+           if (sdone != 0) { /* has src ever been processed ? */
+#if   ENCODE_XS_USEFP == 2
+               more = (1.0*tlen*SvLEN(dst)+sdone-1)/sdone
+                   - SvLEN(dst);
+#elif ENCODE_XS_USEFP
+               more = (1.0*SvLEN(dst)+1)/sdone * sleft;
+#else
+               /* safe until SvLEN(dst) == MAX_INT/16 */
+               more = (16*SvLEN(dst)+1)/sdone/16 * sleft;
+#endif
+           }
+           more += UTF8_MAXLEN; /* insurance policy */
+           d = (U8 *) SvGROW(dst, SvLEN(dst) + more);
+           /* dst need to grow need MORE bytes! */
+           if (ddone >= SvLEN(dst)) {
+               Perl_croak(aTHX_ "Destination couldn't be grown.");
+           }
+           dlen = SvLEN(dst)-ddone-1;
+           d   += ddone;
+           s   += slen;
+           slen = tlen-sdone;
+           continue;
+       }
+       case ENCODE_NOREP:
+           /* encoding */      
+           if (dir == enc->f_utf8) {
+               STRLEN clen;
+               UV ch =
+                   utf8n_to_uvuni(s+slen, (SvCUR(src)-slen),
+                                  &clen, UTF8_ALLOW_ANY|UTF8_CHECK_ONLY);
+               if (check & ENCODE_DIE_ON_ERR) {
+                   Perl_croak(
+                       aTHX_ "\"\\N{U+%" UVxf "}\" does not map to %s, %d",
+                       ch, enc->name[0], __LINE__);
+               }else{
+                   if (check & ENCODE_RETURN_ON_ERR){
+                       if (check & ENCODE_WARN_ON_ERR){
+                           Perl_warner(
+                               aTHX_ packWARN(WARN_UTF8),
+                               "\"\\N{U+%" UVxf "}\" does not map to %s",
+                               ch,enc->name[0]);
+                       }
+                               goto ENCODE_SET_SRC;
+                   }else if (check & ENCODE_PERLQQ){
+                       SV* perlqq =
+                           sv_2mortal(newSVpvf("\\x{%04x}", ch));
+                       sdone += slen + clen;
+                       ddone += dlen + SvCUR(perlqq);
+                       sv_catsv(dst, perlqq);
+                   } else {
+                       /* fallback char */
+                       sdone += slen + clen;
+                       ddone += dlen + enc->replen;
+                       sv_catpvn(dst, (char*)enc->rep, enc->replen);
+                   }                   
+               }
+           }
+           /* decoding */
+           else {
+               if (check & ENCODE_DIE_ON_ERR){
+                   Perl_croak(
+                       aTHX_ "%s \"\\x%02X\" does not map to Unicode (%d)",
+                       enc->name[0], (U8) s[slen], code);
+               }else{
+                   if (check & ENCODE_RETURN_ON_ERR){
+                       if (check & ENCODE_WARN_ON_ERR){
+                           Perl_warner(
+                               aTHX_ packWARN(WARN_UTF8),
+                               "%s \"\\x%02X\" does not map to Unicode (%d)",
+                               enc->name[0], (U8) s[slen], code);
+                       }
+                       goto ENCODE_SET_SRC;
+                   }else if (check & ENCODE_PERLQQ){
+                       SV* perlqq =
+                           sv_2mortal(newSVpvf("\\x%02X", s[slen]));
+                       sdone += slen + 1;
+                       ddone += dlen + SvCUR(perlqq);
+                       sv_catsv(dst, perlqq);
+                   } else {
+                       sdone += slen + 1;
+                       ddone += dlen + strlen(FBCHAR_UTF8);
+                       sv_catpv(dst, FBCHAR_UTF8);
+                   }
+               }
+           }
+           /* settle variables when fallback */
+           d    = (U8 *)SvEND(dst);
+            dlen = SvLEN(dst) - ddone - 1;
+           s    = (U8*)SvPVX(src) + sdone;
+           slen = tlen - sdone;
+           break;
+
+       default:
+           Perl_croak(aTHX_ "Unexpected code %d converting %s %s",
+                      code, (dir == enc->f_utf8) ? "to" : "from",
+                      enc->name[0]);
+           return &PL_sv_undef;
+       }
+    }
+ ENCODE_SET_SRC:
+    if (check && !(check & ENCODE_LEAVE_SRC)){
+       sdone = SvCUR(src) - (slen+sdone);
+       if (sdone) {
+           sv_setpvn(src, (char*)s+slen, sdone);
+       }
+       SvCUR_set(src, sdone);
+    }
+    /* warn("check = 0x%X, code = 0x%d\n", check, code); */
+    if (code && !(check & ENCODE_RETURN_ON_ERR)) {
+       return &PL_sv_undef;
+    }
+
+    SvCUR_set(dst, dlen+ddone);
+    SvPOK_only(dst);
+
+#if ENCODE_XS_PROFILE
+    if (SvCUR(dst) > SvCUR(src)){
+       Perl_warn(aTHX_
+                 "SvLEN(dst)=%d, SvCUR(dst)=%d. %d bytes unused(%f %%)\n",
+                 SvLEN(dst), SvCUR(dst), SvLEN(dst) - SvCUR(dst),
+                 (SvLEN(dst) - SvCUR(dst))*1.0/SvLEN(dst)*100.0);
+    }
+#endif
 
+ ENCODE_END:
+    *SvEND(dst) = '\0';
+    return dst;
 }
 
-IV
-PerlIOEncode_fill(PerlIO *f)
+MODULE = Encode                PACKAGE = Encode::XS    PREFIX = Method_
+
+PROTOTYPES: ENABLE
+
+void
+Method_name(obj)
+SV *   obj
+CODE:
 {
- PerlIOEncode *e = PerlIOSelf(f,PerlIOEncode);
- dTHX;
- dSP;
- IV code;
- Break();
- code = PerlIOBuf_fill(f);
- if (code == 0)
-  {
-   SV *uni;
-   SvCUR_set(e->bufsv, e->base.end - e->base.buf);
-   SvUTF8_off(e->bufsv);
-   ENTER;
-   SAVETMPS;
-   PUSHMARK(sp);
-   XPUSHs(e->enc);
-   XPUSHs(e->bufsv);
-   XPUSHs(&PL_sv_yes);
-   PUTBACK;
-   if (perl_call_method("toUnicode",G_SCALAR) != 1)
-    code = -1;
-   SPAGAIN;
-   uni = POPs;
-   PUTBACK;
-   sv_setsv(e->bufsv,uni);
-   sv_utf8_upgrade(e->bufsv);
-   e->base.buf    = SvPVX(e->bufsv);
-   e->base.end    = e->base.buf+SvCUR(e->bufsv);
-   e->base.ptr    = e->base.buf;
-   FREETMPS;
-   LEAVE;
-  }
- return code;
+    encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
+    ST(0) = sv_2mortal(newSVpvn(enc->name[0],strlen(enc->name[0])));
+    XSRETURN(1);
 }
 
-IV
-PerlIOEncode_flush(PerlIO *f)
+void
+Method_decode(obj,src,check = 0)
+SV *   obj
+SV *   src
+int    check
+CODE:
 {
- PerlIOEncode *e = PerlIOSelf(f,PerlIOEncode);
- IV code = 0;
- dTHX;
- if (e->bufsv && (PerlIOBase(f)->flags & (PERLIO_F_RDBUF|PERLIO_F_WRBUF)))
-  {
-   dSP;
-   SV *str;
-   char *s;
-   STRLEN len;
-   ENTER;
-   SAVETMPS;
-   PUSHMARK(sp);
-   XPUSHs(e->enc);
-   SvCUR_set(e->bufsv, e->base.end - e->base.buf);
-   SvUTF8_on(e->bufsv);
-   XPUSHs(e->bufsv);
-   XPUSHs(&PL_sv_yes);
-   PUTBACK;
-   if (perl_call_method("fromUnicode",G_SCALAR) != 1)
-    code = -1;
-   SPAGAIN;
-   str = POPs;
-   PUTBACK;
-   sv_setsv(e->bufsv,str);
-   SvUTF8_off(e->bufsv);
-   e->base.buf = SvPVX(e->bufsv);
-   e->base.ptr = e->base.buf+SvCUR(e->bufsv);
-   FREETMPS;
-   LEAVE;
-   if (PerlIOBuf_flush(f) != 0)
-    code = -1;
-  }
- return code;
+    encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
+    ST(0) = encode_method(aTHX_ enc, enc->t_utf8, src, check);
+    SvUTF8_on(ST(0));
+    XSRETURN(1);
 }
 
-IV
-PerlIOEncode_close(PerlIO *f)
+void
+Method_encode(obj,src,check = 0)
+SV *   obj
+SV *   src
+int    check
+CODE:
 {
- PerlIOEncode *e = PerlIOSelf(f,PerlIOEncode);
- IV code = PerlIOBase_close(f);
- dTHX;
- if (e->bufsv)
-  {
-   SvREFCNT_dec(e->bufsv);
-   e->bufsv = Nullsv;
-  }
- e->base.buf = NULL;
- e->base.ptr = NULL;
- e->base.end = NULL;
- PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF|PERLIO_F_WRBUF);
- return code;
+    encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
+    sv_utf8_upgrade(src);
+    ST(0) = encode_method(aTHX_ enc, enc->f_utf8, src, check);
+    XSRETURN(1);
 }
 
-PerlIO_funcs PerlIO_encode = {
- "encode",
- sizeof(PerlIOEncode),
- PERLIO_K_BUFFERED,
- PerlIOBase_fileno,
- PerlIOBuf_fdopen,
- PerlIOBuf_open,
- PerlIOBuf_reopen,
- PerlIOEncode_pushed,
- PerlIOEncode_popped,
- PerlIOBuf_read,
- PerlIOBuf_unread,
- PerlIOBuf_write,
- PerlIOBuf_seek,
- PerlIOBuf_tell,
- PerlIOEncode_close,
- PerlIOEncode_flush,
- PerlIOEncode_fill,
- PerlIOBase_eof,
- PerlIOBase_error,
- PerlIOBase_clearerr,
- PerlIOBuf_setlinebuf,
- PerlIOEncode_get_base,
- PerlIOBuf_bufsiz,
- PerlIOBuf_get_ptr,
- PerlIOBuf_get_cnt,
- PerlIOBuf_set_ptrcnt,
-};
-#endif
-
-void call_failure (SV *routine, U8* done, U8* dest, U8* orig) {}
-
 MODULE = Encode         PACKAGE = Encode
 
 PROTOTYPES: ENABLE
 
 I32
 _bytes_to_utf8(sv, ...)
-        SV *    sv
-      CODE:
-        {
-          SV * encoding = items == 2 ? ST(1) : Nullsv;
-
-          if (encoding)
-            RETVAL = _encoded_bytes_to_utf8(sv, SvPV_nolen(encoding));
-          else {
-            STRLEN len;
-            U8*    s = (U8*)SvPV(sv, len);
-            U8*    converted;
-
-            converted = bytes_to_utf8(s, &len); /* This allocs */
-            sv_setpvn(sv, (char *)converted, len);
-            SvUTF8_on(sv); /* XXX Should we? */
-            Safefree(converted);                /* ... so free it */
-            RETVAL = len;
-          }
-        }
-      OUTPUT:
-        RETVAL
+SV *    sv
+CODE:
+{
+    SV * encoding = items == 2 ? ST(1) : Nullsv;
+
+    if (encoding)
+    RETVAL = _encoded_bytes_to_utf8(sv, SvPV_nolen(encoding));
+    else {
+       STRLEN len;
+       U8*    s = (U8*)SvPV(sv, len);
+       U8*    converted;
+
+       converted = bytes_to_utf8(s, &len); /* This allocs */
+       sv_setpvn(sv, (char *)converted, len);
+       SvUTF8_on(sv); /* XXX Should we? */
+       Safefree(converted);                /* ... so free it */
+       RETVAL = len;
+    }
+}
+OUTPUT:
+    RETVAL
 
 I32
 _utf8_to_bytes(sv, ...)
-        SV *    sv
-      CODE:
-        {
-          SV * to    = items > 1 ? ST(1) : Nullsv;
-          SV * check = items > 2 ? ST(2) : Nullsv;
-
-          if (to)
-            RETVAL = _encoded_utf8_to_bytes(sv, SvPV_nolen(to));
-          else {
-            STRLEN len;
-            U8 *s = (U8*)SvPV(sv, len);
-
-            if (SvTRUE(check)) {
-              /* Must do things the slow way */
-              U8 *dest;
-              U8 *src  = (U8*)savepv((char *)s); /* We need a copy to pass to check() */
-              U8 *send = s + len;
-
-              New(83, dest, len, U8); /* I think */
-
-              while (s < send) {
-                if (*s < 0x80)
-                  *dest++ = *s++;
-                else {
-                  STRLEN ulen;
-                 UV uv = *s++;
-
-                  /* Have to do it all ourselves because of error routine,
-                    aargh. */
-                 if (!(uv & 0x40))
-                   goto failure;
-                 if      (!(uv & 0x20)) { ulen = 2;  uv &= 0x1f; }
-                 else if (!(uv & 0x10)) { ulen = 3;  uv &= 0x0f; }
-                 else if (!(uv & 0x08)) { ulen = 4;  uv &= 0x07; }
-                 else if (!(uv & 0x04)) { ulen = 5;  uv &= 0x03; }
-                 else if (!(uv & 0x02)) { ulen = 6;  uv &= 0x01; }
-                 else if (!(uv & 0x01)) { ulen = 7;  uv = 0; }
-                 else                   { ulen = 13; uv = 0; }
-               
-                 /* Note change to utf8.c variable naming, for variety */
-                 while (ulen--) {
-                   if ((*s & 0xc0) != 0x80)
-                     goto failure;
+SV *    sv
+CODE:
+{
+    SV * to    = items > 1 ? ST(1) : Nullsv;
+    SV * check = items > 2 ? ST(2) : Nullsv;
+
+    if (to) {
+       RETVAL = _encoded_utf8_to_bytes(sv, SvPV_nolen(to));
+    } else {
+       STRLEN len;
+       U8 *s = (U8*)SvPV(sv, len);
+
+       RETVAL = 0;
+       if (SvTRUE(check)) {
+           /* Must do things the slow way */
+           U8 *dest;
+            /* We need a copy to pass to check() */
+           U8 *src  = (U8*)savepv((char *)s);
+           U8 *send = s + len;
+
+           New(83, dest, len, U8); /* I think */
+
+           while (s < send) {
+                if (*s < 0x80){
+                   *dest++ = *s++;
+                } else {
+                   STRLEN ulen;
+                   UV uv = *s++;
+
+                   /* Have to do it all ourselves because of error routine,
+                      aargh. */
+                   if (!(uv & 0x40)){ goto failure; }
+                   if      (!(uv & 0x20)) { ulen = 2;  uv &= 0x1f; }
+                   else if (!(uv & 0x10)) { ulen = 3;  uv &= 0x0f; }
+                   else if (!(uv & 0x08)) { ulen = 4;  uv &= 0x07; }
+                   else if (!(uv & 0x04)) { ulen = 5;  uv &= 0x03; }
+                   else if (!(uv & 0x02)) { ulen = 6;  uv &= 0x01; }
+                   else if (!(uv & 0x01)) { ulen = 7;  uv = 0; }
+                   else                   { ulen = 13; uv = 0; }
                
-                   else
-                     uv = (uv << 6) | (*s++ & 0x3f);
+                   /* Note change to utf8.c variable naming, for variety */
+                   while (ulen--) {
+                       if ((*s & 0xc0) != 0x80){
+                           goto failure;
+                       } else {
+                           uv = (uv << 6) | (*s++ & 0x3f);
+                       }
                  }
                  if (uv > 256) {
                  failure:
-                   call_failure(check, s, dest, src);
-                   /* Now what happens? */
+                     call_failure(check, s, dest, src);
+                     /* Now what happens? */
                  }
                  *dest++ = (U8)uv;
-               }
-               }
-           } else
-             RETVAL = (utf8_to_bytes(s, &len) ? len : 0);
-         }
-       }
-      OUTPUT:
-       RETVAL
-
-SV *
-_chars_to_utf8(sv, from, ...)
-       SV *    sv
-       SV *    from
-      CODE:
-       {
-         SV * check = items == 3 ? ST(2) : Nullsv;
-         RETVAL = &PL_sv_undef;
+               }
+           }
+       } else {
+           RETVAL = (utf8_to_bytes(s, &len) ? len : 0);
        }
-      OUTPUT:
-       RETVAL
-
-SV *
-_utf8_to_chars(sv, to, ...)
-       SV *    sv
-       SV *    to
-      CODE:
-       {
-         SV * check = items == 3 ? ST(2) : Nullsv;
-         RETVAL = &PL_sv_undef;
-       }
-      OUTPUT:
-       RETVAL
-
-SV *
-_utf8_to_chars_check(sv, ...)
-       SV *    sv
-      CODE:
-       {
-         SV * check = items == 2 ? ST(1) : Nullsv;
-         RETVAL = &PL_sv_undef;
-       }
-      OUTPUT:
-       RETVAL
-
-SV *
-_bytes_to_chars(sv, from, ...)
-       SV *    sv
-       SV *    from
-      CODE:
-       {
-         SV * check = items == 3 ? ST(2) : Nullsv;
-         RETVAL = &PL_sv_undef;
-       }
-      OUTPUT:
-       RETVAL
-
-SV *
-_chars_to_bytes(sv, to, ...)
-       SV *    sv
-       SV *    to
-      CODE:
-       {
-         SV * check = items == 3 ? ST(2) : Nullsv;
-         RETVAL = &PL_sv_undef;
-       }
-      OUTPUT:
-       RETVAL
-
-SV *
-_from_to(sv, from, to, ...)
-       SV *    sv
-       SV *    from
-       SV *    to
-      CODE:
-       {
-         SV * check = items == 4 ? ST(3) : Nullsv;
-         RETVAL = &PL_sv_undef;
-       }
-      OUTPUT:
-       RETVAL
+    }
+}
+OUTPUT:
+    RETVAL
 
 bool
-_is_utf8(sv, ...)
-       SV *    sv
-      CODE:
-       {
-         SV *  check = items == 2 ? ST(1) : Nullsv;
-         if (SvPOK(sv)) {
-           RETVAL = SvUTF8(sv) ? 1 : 0;
-           if (RETVAL &&
-               SvTRUE(check) &&
-               !is_utf8_string((U8*)SvPVX(sv), SvCUR(sv)))
-             RETVAL = FALSE;
-         } else {
+is_utf8(sv, check = 0)
+SV *   sv
+int    check
+CODE:
+{
+    if (SvGMAGICAL(sv)) /* it could be $1, for example */
+       sv = newSVsv(sv); /* GMAGIG will be done */
+    if (SvPOK(sv)) {
+       RETVAL = SvUTF8(sv) ? TRUE : FALSE;
+       if (RETVAL &&
+           check  &&
+           !is_utf8_string((U8*)SvPVX(sv), SvCUR(sv)))
            RETVAL = FALSE;
-         }
-       }
-      OUTPUT:
-       RETVAL
-
-SV *
-_on_utf8(sv)
-       SV *    sv
-      CODE:
-       {
-         if (SvPOK(sv)) {
-           SV *rsv = newSViv(SvUTF8(sv));
-           RETVAL = rsv;
-           SvUTF8_on(sv);
-         } else {
-           RETVAL = &PL_sv_undef;
-         }
-       }
-      OUTPUT:
-       RETVAL
+    } else {
+       RETVAL = FALSE;
+    }
+    if (sv != ST(0))
+       SvREFCNT_dec(sv); /* it was a temp copy */
+}
+OUTPUT:
+    RETVAL
 
 SV *
-_off_utf8(sv)
-       SV *    sv
-      CODE:
-       {
-         if (SvPOK(sv)) {
-           SV *rsv = newSViv(SvUTF8(sv));
-           RETVAL = rsv;
-           SvUTF8_off(sv);
-         } else {
-           RETVAL = &PL_sv_undef;
-         }
-       }
-      OUTPUT:
-       RETVAL
+_utf8_on(sv)
+SV *   sv
+CODE:
+{
+    if (SvPOK(sv)) {
+       SV *rsv = newSViv(SvUTF8(sv));
+       RETVAL = rsv;
+       SvUTF8_on(sv);
+    } else {
+       RETVAL = &PL_sv_undef;
+    }
+}
+OUTPUT:
+    RETVAL
 
 SV *
-_utf_to_utf(sv, from, to, ...)
-       SV *    sv
-       SV *    from
-       SV *    to
-      CODE:
-       {
-         SV * check = items == 4 ? ST(3) : Nullsv;
-         RETVAL = &PL_sv_undef;
-       }
-      OUTPUT:
-       RETVAL
+_utf8_off(sv)
+SV *   sv
+CODE:
+{
+    if (SvPOK(sv)) {
+       SV *rsv = newSViv(SvUTF8(sv));
+       RETVAL = rsv;
+       SvUTF8_off(sv);
+    } else {
+       RETVAL = &PL_sv_undef;
+    }
+}
+OUTPUT:
+    RETVAL
+
+PROTOTYPES: DISABLE
+
+
+int
+DIE_ON_ERR()
+CODE:
+    RETVAL = ENCODE_DIE_ON_ERR;
+OUTPUT:
+    RETVAL
+
+int
+WARN_ON_ERR()
+CODE:
+    RETVAL = ENCODE_WARN_ON_ERR;
+OUTPUT:
+    RETVAL
+
+int
+LEAVE_SRC()
+CODE:
+    RETVAL = ENCODE_LEAVE_SRC;
+OUTPUT:
+    RETVAL
+
+int
+RETURN_ON_ERR()
+CODE:
+    RETVAL = ENCODE_RETURN_ON_ERR;
+OUTPUT:
+    RETVAL
+
+int
+PERLQQ()
+CODE:
+    RETVAL = ENCODE_PERLQQ;
+OUTPUT:
+    RETVAL
+
+int
+FB_DEFAULT()
+CODE:
+    RETVAL = ENCODE_FB_DEFAULT;
+OUTPUT:
+    RETVAL
+
+int
+FB_CROAK()
+CODE:
+    RETVAL = ENCODE_FB_CROAK;
+OUTPUT:
+    RETVAL
+
+int
+FB_QUIET()
+CODE:
+    RETVAL = ENCODE_FB_QUIET;
+OUTPUT:
+    RETVAL
+
+int
+FB_WARN()
+CODE:
+    RETVAL = ENCODE_FB_WARN;
+OUTPUT:
+    RETVAL
+
+int
+FB_PERLQQ()
+CODE:
+    RETVAL = ENCODE_FB_PERLQQ;
+OUTPUT:
+    RETVAL
 
 BOOT:
 {
-#ifdef USE_PERLIO
- PerlIO_define_layer(&PerlIO_encode);
-#endif
+#include "def_t.h"
+#include "def_t.exh"
 }