/* $Id: Encode.xs,v 2.4 2005/05/16 18:46:36 dankogai Exp dankogai $ */ #define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define U8 U8 #include "encode.h" # define PERLIO_MODNAME "PerlIO::encoding" # define PERLIO_FILENAME "PerlIO/encoding.pm" /* 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 /* 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) #define UTF8_ALLOW_STRICT 0 #define UTF8_ALLOW_NONSTRICT (UTF8_ALLOW_ANY & \ ~(UTF8_ALLOW_CONTINUATION | \ UTF8_ALLOW_NON_CONTINUATION | \ UTF8_ALLOW_LONG)) void Encode_XSEncoding(pTHX_ encode_t * enc) 148 { 148 dSP; 148 HV *stash = gv_stashpv("Encode::XS", TRUE); 148 SV *sv = sv_bless(newRV_noinc(newSViv(PTR2IV(enc))), stash); 148 int i = 0; 148 PUSHMARK(sp); 148 XPUSHs(sv); 296 while (enc->name[i]) { 148 const char *name = enc->name[i++]; 148 XPUSHs(sv_2mortal(newSVpvn(name, strlen(name)))); } 148 PUTBACK; 148 call_pv("Encode::define_encoding", G_DISCARD); 148 SvREFCNT_dec(sv); } void call_failure(SV * routine, U8 * done, U8 * dest, U8 * orig) ###### { /* Exists for breakpointing */ } #define ERR_ENCODE_NOMAP "\"\\x{%04" UVxf "}\" does not map to %s" #define ERR_DECODE_NOMAP "%s \"\\x%02" UVXf "\" does not map to Unicode" static SV * encode_method(pTHX_ encode_t * enc, encpage_t * dir, SV * src, int check, STRLEN * offset, SV * term, int * retcode) 39206 { 39206 STRLEN slen; 39206 U8 *s = (U8 *) SvPV(src, slen); 39206 STRLEN tlen = slen; 39206 STRLEN ddone = 0; 39206 STRLEN sdone = 0; /* We allocate slen+1. PerlIO dumps core if this value is smaller than this. */ 39206 SV *dst = sv_2mortal(newSV(slen+1)); 39206 U8 *d = (U8 *)SvPVX(dst); 39206 STRLEN dlen = SvLEN(dst)-1; 39206 int code = 0; 39206 STRLEN trmlen = 0; 39206 U8 *trm = term ? (U8*) SvPV(term, trmlen) : NULL; 39206 if (offset) { 223 s += *offset; 223 if (slen > *offset){ /* safeguard against slen overflow */ 223 slen -= *offset; }else{ ###### slen = 0; } 223 tlen = slen; } 39206 if (slen == 0){ 46 SvCUR_set(dst, 0); 46 SvPOK_only(dst); 46 goto ENCODE_END; } 40946 while( (code = do_encode(dir, s, &slen, d, dlen, &dlen, !check, trm, trmlen)) ) { 2164 SvCUR_set(dst, dlen+ddone); 2164 SvPOK_only(dst); 2164 if (code == ENCODE_FALLBACK || code == ENCODE_PARTIAL || code == ENCODE_FOUND_TERM) { 1828 break; } 1828 switch (code) { case ENCODE_NOSPACE: { 1139 STRLEN more = 0; /* make sure you initialize! */ 1139 STRLEN sleft; 1139 sdone += slen; 1139 ddone += dlen; 1139 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 1139 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 1139 more = (STRLEN)((1.0*SvLEN(dst)+1)/sdone * sleft); #else /* safe until SvLEN(dst) == MAX_INT/16 */ more = (16*SvLEN(dst)+1)/sdone/16 * sleft; #endif } 1139 more += UTF8_MAXLEN; /* insurance policy */ 1139 d = (U8 *) SvGROW(dst, SvLEN(dst) + more); /* dst need to grow need MORE bytes! */ 1139 if (ddone >= SvLEN(dst)) { ###### Perl_croak(aTHX_ "Destination couldn't be grown."); } 1139 dlen = SvLEN(dst)-ddone-1; 1139 d += ddone; 1139 s += slen; 1139 slen = tlen-sdone; 1139 continue; } case ENCODE_NOREP: /* encoding */ 689 if (dir == enc->f_utf8) { 645 STRLEN clen; 645 UV ch = utf8n_to_uvuni(s+slen, (SvCUR(src)-slen), 645 &clen, UTF8_ALLOW_ANY|UTF8_CHECK_ONLY); 645 if (check & ENCODE_DIE_ON_ERR) { 1 Perl_croak(aTHX_ ERR_ENCODE_NOMAP, (UV)ch, enc->name[0]); 644 return &PL_sv_undef; /* never reaches but be safe */ } 644 if (check & ENCODE_WARN_ON_ERR){ 130 Perl_warner(aTHX_ packWARN(WARN_UTF8), ERR_ENCODE_NOMAP, (UV)ch, enc->name[0]); } 644 if (check & ENCODE_RETURN_ON_ERR){ 2 goto ENCODE_SET_SRC; } 642 if (check & (ENCODE_PERLQQ|ENCODE_HTMLCREF|ENCODE_XMLCREF)){ 386 SV* subchar = newSVpvf(check & ENCODE_PERLQQ ? "\\x{%04"UVxf"}" : check & ENCODE_HTMLCREF ? "&#%" UVuf ";" : 386 "&#x%" UVxf ";", (UV)ch); 386 sdone += slen + clen; 386 ddone += dlen + SvCUR(subchar); 386 sv_catsv(dst, subchar); 386 SvREFCNT_dec(subchar); } else { /* fallback char */ 256 sdone += slen + clen; 256 ddone += dlen + enc->replen; 256 sv_catpvn(dst, (char*)enc->rep, enc->replen); } } /* decoding */ else { 44 if (check & ENCODE_DIE_ON_ERR){ 2 Perl_croak(aTHX_ ERR_DECODE_NOMAP, enc->name[0], (UV)s[slen]); 42 return &PL_sv_undef; /* never reaches but be safe */ } 42 if (check & ENCODE_WARN_ON_ERR){ ###### Perl_warner( aTHX_ packWARN(WARN_UTF8), ERR_DECODE_NOMAP, enc->name[0], (UV)s[slen]); } 42 if (check & ENCODE_RETURN_ON_ERR){ 37 goto ENCODE_SET_SRC; } 5 if (check & (ENCODE_PERLQQ|ENCODE_HTMLCREF|ENCODE_XMLCREF)){ 1 SV* subchar = newSVpvf("\\x%02" UVXf, (UV)s[slen]); 1 sdone += slen + 1; 1 ddone += dlen + SvCUR(subchar); 1 sv_catsv(dst, subchar); 1 SvREFCNT_dec(subchar); } else { 4 sdone += slen + 1; 4 ddone += dlen + strlen(FBCHAR_UTF8); 4 sv_catpv(dst, FBCHAR_UTF8); } } /* settle variables when fallback */ 647 d = (U8 *)SvEND(dst); 647 dlen = SvLEN(dst) - ddone - 1; 647 s = (U8*)SvPVX(src) + sdone; 647 slen = tlen - sdone; 647 break; default: ###### Perl_croak(aTHX_ "Unexpected code %d converting %s %s", code, (dir == enc->f_utf8) ? "to" : "from", enc->name[0]); 39157 return &PL_sv_undef; } } ENCODE_SET_SRC: 39157 if (check && !(check & ENCODE_LEAVE_SRC)){ 16830 sdone = SvCUR(src) - (slen+sdone); 16830 if (sdone) { 152 sv_setpvn(src, (char*)s+slen, sdone); } 16830 SvCUR_set(src, sdone); } /* warn("check = 0x%X, code = 0x%d\n", check, code); */ 39157 SvCUR_set(dst, dlen+ddone); 39157 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 39157 if (offset) 223 *offset += sdone + slen; ENCODE_END: 39203 *SvEND(dst) = '\0'; 39203 if (retcode) *retcode = code; 39203 return dst; } static bool strict_utf8(pTHX_ SV* sv) 352 { 352 HV* hv; 352 SV** svp; 352 sv = SvRV(sv); 352 if (!sv || SvTYPE(sv) != SVt_PVHV) ###### return 0; 352 hv = (HV*)sv; 352 svp = hv_fetch(hv, "strict_utf8", 11, 0); 352 if (!svp) 270 return 0; 82 return SvTRUE(*svp); } static U8* process_utf8(pTHX_ SV* dst, U8* s, U8* e, int check, bool encode, bool strict, bool stop_at_partial) 335 { 335 UV uv; 335 STRLEN ulen; 335 SvPOK_only(dst); 335 SvCUR_set(dst,0); 65860 while (s < e) { 65563 if (UTF8_IS_INVARIANT(*s)) { 17432 sv_catpvn(dst, (char *)s, 1); 17432 s++; 17432 continue; } 48131 if (UTF8_IS_START(*s)) { 47778 U8 skip = UTF8SKIP(s); 47778 if ((s + skip) > e) { /* Partial character */ /* XXX could check that rest of bytes are UTF8_IS_CONTINUATION(ch) */ 19 if (stop_at_partial) 8 break; 47759 goto malformed_byte; } 47759 uv = utf8n_to_uvuni(s, e - s, &ulen, UTF8_CHECK_ONLY | (strict ? UTF8_ALLOW_STRICT : UTF8_ALLOW_NONSTRICT) ); #if 1 /* perl-5.8.6 and older do not check UTF8_ALLOW_LONG */ 47759 if (strict && uv > PERL_UNICODE_MAX) 6 ulen = -1; #endif 47759 if (ulen == -1) { 316 if (strict) { 15 uv = utf8n_to_uvuni(s, e - s, &ulen, UTF8_CHECK_ONLY | UTF8_ALLOW_NONSTRICT); 15 if (ulen == -1) 1 goto malformed_byte; 47443 goto malformed; } 47443 goto malformed_byte; } /* Whole char is good */ 47443 sv_catpvn(dst,(char *)s,skip); 47443 s += skip; 47443 continue; } /* If we get here there is something wrong with alleged UTF-8 */ malformed_byte: 666 uv = (UV)*s; 666 ulen = 1; malformed: 680 if (check & ENCODE_DIE_ON_ERR){ 15 if (encode) 13 Perl_croak(aTHX_ ERR_ENCODE_NOMAP, uv, "utf8"); else 2 Perl_croak(aTHX_ ERR_DECODE_NOMAP, "utf8", uv); } 665 if (check & ENCODE_WARN_ON_ERR){ 136 if (encode) ###### Perl_warner(aTHX_ packWARN(WARN_UTF8), ERR_ENCODE_NOMAP, uv, "utf8"); else 136 Perl_warner(aTHX_ packWARN(WARN_UTF8), ERR_DECODE_NOMAP, "utf8", uv); } 665 if (check & ENCODE_RETURN_ON_ERR) { 15 break; } 650 if (check & (ENCODE_PERLQQ|ENCODE_HTMLCREF|ENCODE_XMLCREF)){ 391 SV* subchar = newSVpvf(check & ENCODE_PERLQQ ? (ulen == 1 ? "\\x%02" UVXf : "\\x{%04" UVXf "}"): check & ENCODE_HTMLCREF ? "&#%" UVuf ";" : 391 "&#x%" UVxf ";", uv); 391 sv_catsv(dst, subchar); 391 SvREFCNT_dec(subchar); } else { 259 sv_catpv(dst, FBCHAR_UTF8); } 650 s += ulen; } 320 *SvEND(dst) = '\0'; 320 return s; } MODULE = Encode PACKAGE = Encode::utf8 PREFIX = Method_ PROTOTYPES: DISABLE void Method_decode_xs(obj,src,check = 0) SV * obj SV * src int check CODE: { 297 STRLEN slen; 297 U8 *s = (U8 *) SvPV(src, slen); 297 U8 *e = (U8 *) SvEND(src); 297 SV *dst = newSV(slen>0?slen:1); /* newSV() abhors 0 -- inaba */ /* * PerlIO check -- we assume the object is of PerlIO if renewed */ 297 int renewed = 0; 297 dSP; ENTER; SAVETMPS; 297 PUSHMARK(sp); 297 XPUSHs(obj); 297 PUTBACK; 297 if (call_method("renewed",G_SCALAR) == 1) { 297 SPAGAIN; 297 renewed = POPi; 297 PUTBACK; #if 0 fprintf(stderr, "renewed == %d\n", renewed); #endif } 297 FREETMPS; LEAVE; /* end PerlIO check */ 297 if (SvUTF8(src)) { 21 s = utf8_to_bytes(s,&slen); 21 if (s) { 21 SvCUR_set(src,slen); 21 SvUTF8_off(src); 21 e = s+slen; } else { ###### croak("Cannot decode string with wide characters"); } } 297 s = process_utf8(aTHX_ dst, s, e, check, 0, strict_utf8(aTHX_ obj), renewed); /* Clear out translated part of source unless asked not to */ 295 if (check && !(check & ENCODE_LEAVE_SRC)){ 40 slen = e-s; 40 if (slen) { 23 sv_setpvn(src, (char*)s, slen); } 40 SvCUR_set(src, slen); } 295 SvUTF8_on(dst); 295 ST(0) = sv_2mortal(dst); 295 XSRETURN(1); } void Method_encode_xs(obj,src,check = 0) SV * obj SV * src int check CODE: { 64 STRLEN slen; 64 U8 *s = (U8 *) SvPV(src, slen); 64 U8 *e = (U8 *) SvEND(src); 64 SV *dst = newSV(slen>0?slen:1); /* newSV() abhors 0 -- inaba */ 64 if (SvUTF8(src)) { /* Already encoded */ 55 if (strict_utf8(aTHX_ obj)) { 38 s = process_utf8(aTHX_ dst, s, e, check, 1, 1, 0); } else { /* trust it and just copy the octets */ 17 sv_setpvn(dst,(char *)s,(e-s)); 17 s = e; } } else { /* Native bytes - can always encode */ 9 U8 *d = (U8 *) SvGROW(dst, 2*slen+1); /* +1 or assertion will botch */ 33 while (s < e) { 24 UV uv = NATIVE_TO_UNI((UV) *s++); 24 if (UNI_IS_INVARIANT(uv)) 22 *d++ = (U8)UTF_TO_NATIVE(uv); else { 2 *d++ = (U8)UTF8_EIGHT_BIT_HI(uv); 2 *d++ = (U8)UTF8_EIGHT_BIT_LO(uv); } } 9 SvCUR_set(dst, d- (U8 *)SvPVX(dst)); 9 *SvEND(dst) = '\0'; } /* Clear out translated part of source unless asked not to */ 51 if (check && !(check & ENCODE_LEAVE_SRC)){ 9 slen = e-s; 9 if (slen) { ###### sv_setpvn(src, (char*)s, slen); } 9 SvCUR_set(src, slen); } 51 SvPOK_only(dst); 51 SvUTF8_off(dst); 51 ST(0) = sv_2mortal(dst); 51 XSRETURN(1); } MODULE = Encode PACKAGE = Encode::XS PREFIX = Method_ PROTOTYPES: ENABLE void Method_renew(obj) SV * obj CODE: { 53 XSRETURN(1); } int Method_renewed(obj) SV * obj CODE: ###### RETVAL = 0; OUTPUT: RETVAL void Method_name(obj) SV * obj CODE: { 984 encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj))); 984 ST(0) = sv_2mortal(newSVpvn(enc->name[0],strlen(enc->name[0]))); 984 XSRETURN(1); } void Method_cat_decode(obj, dst, src, off, term, check = 0) SV * obj SV * dst SV * src SV * off SV * term int check CODE: { 223 encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj))); 223 STRLEN offset = (STRLEN)SvIV(off); 223 int code = 0; 223 if (SvUTF8(src)) { ###### sv_utf8_downgrade(src, FALSE); } sv_catsv(dst, encode_method(aTHX_ enc, enc->t_utf8, src, check, 223 &offset, term, &code)); 223 SvIV_set(off, (IV)offset); 223 if (code == ENCODE_FOUND_TERM) { 223 ST(0) = &PL_sv_yes; }else{ ###### ST(0) = &PL_sv_no; } 223 XSRETURN(1); } void Method_decode(obj,src,check = 0) SV * obj SV * src int check CODE: { 4410 encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj))); 4410 if (SvUTF8(src)) { 248 sv_utf8_downgrade(src, FALSE); } 4410 ST(0) = encode_method(aTHX_ enc, enc->t_utf8, src, check, NULL, Nullsv, NULL); 4408 SvUTF8_on(ST(0)); 4408 XSRETURN(1); } void Method_encode(obj,src,check = 0) SV * obj SV * src int check CODE: { 34573 encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj))); 34573 sv_utf8_upgrade(src); 34573 ST(0) = encode_method(aTHX_ enc, enc->f_utf8, src, check, NULL, Nullsv, NULL); 34572 XSRETURN(1); } void Method_needs_lines(obj) SV * obj CODE: { /* encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj))); */ 53 ST(0) = &PL_sv_no; 53 XSRETURN(1); } void Method_perlio_ok(obj) SV * obj CODE: { /* encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj))); */ /* require_pv(PERLIO_FILENAME); */ 8 eval_pv("require PerlIO::encoding", 0); 8 if (SvTRUE(get_sv("@", 0))) { ###### ST(0) = &PL_sv_no; }else{ 8 ST(0) = &PL_sv_yes; } 8 XSRETURN(1); } 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 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); ###### 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; } /* 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? */ } ###### *dest++ = (U8)uv; } } } else { ###### RETVAL = (utf8_to_bytes(s, &len) ? len : 0); } } } OUTPUT: RETVAL bool is_utf8(sv, check = 0) SV * sv int check CODE: { 545 if (SvGMAGICAL(sv)) /* it could be $1, for example */ 1 sv = newSVsv(sv); /* GMAGIG will be done */ 545 if (SvPOK(sv)) { 545 RETVAL = SvUTF8(sv) ? TRUE : FALSE; 545 if (RETVAL && check && !is_utf8_string((U8*)SvPVX(sv), SvCUR(sv))) ###### RETVAL = FALSE; } else { ###### RETVAL = FALSE; } 545 if (sv != ST(0)) 1 SvREFCNT_dec(sv); /* it was a temp copy */ } OUTPUT: RETVAL SV * _utf8_on(sv) SV * sv CODE: { 1 if (SvPOK(sv)) { 1 SV *rsv = newSViv(SvUTF8(sv)); 1 RETVAL = rsv; 1 SvUTF8_on(sv); } else { ###### RETVAL = &PL_sv_undef; } } OUTPUT: RETVAL SV * _utf8_off(sv) SV * sv CODE: { 1 if (SvPOK(sv)) { 1 SV *rsv = newSViv(SvUTF8(sv)); 1 RETVAL = rsv; 1 SvUTF8_off(sv); } else { ###### RETVAL = &PL_sv_undef; } } OUTPUT: RETVAL int DIE_ON_ERR() CODE: ###### RETVAL = ENCODE_DIE_ON_ERR; OUTPUT: RETVAL int WARN_ON_ERR() CODE: 19 RETVAL = ENCODE_WARN_ON_ERR; OUTPUT: RETVAL int LEAVE_SRC() CODE: 1489 RETVAL = ENCODE_LEAVE_SRC; OUTPUT: RETVAL int RETURN_ON_ERR() CODE: ###### RETVAL = ENCODE_RETURN_ON_ERR; OUTPUT: RETVAL int PERLQQ() CODE: 35 RETVAL = ENCODE_PERLQQ; OUTPUT: RETVAL int HTMLCREF() CODE: 1 RETVAL = ENCODE_HTMLCREF; OUTPUT: RETVAL int XMLCREF() CODE: ###### RETVAL = ENCODE_XMLCREF; OUTPUT: RETVAL int FB_DEFAULT() CODE: 2 RETVAL = ENCODE_FB_DEFAULT; OUTPUT: RETVAL int FB_CROAK() CODE: 10 RETVAL = ENCODE_FB_CROAK; OUTPUT: RETVAL int FB_QUIET() CODE: 204 RETVAL = ENCODE_FB_QUIET; OUTPUT: RETVAL int FB_WARN() CODE: 2 RETVAL = ENCODE_FB_WARN; OUTPUT: RETVAL int FB_PERLQQ() CODE: 1518 RETVAL = ENCODE_FB_PERLQQ; OUTPUT: RETVAL int FB_HTMLCREF() CODE: 2 RETVAL = ENCODE_FB_HTMLCREF; OUTPUT: RETVAL int FB_XMLCREF() CODE: 2 RETVAL = ENCODE_FB_XMLCREF; OUTPUT: RETVAL BOOT: { #include "def_t.h" #include "def_t.exh" } }