No semicolons after blocks.
[p5sagit/p5-mst-13.2.git] / ext / Encode / Encode.xs
1 /*
2  $Id: Encode.xs,v 1.33 2002/04/22 03:43:05 dankogai Exp $
3  */
4
5 #define PERL_NO_GET_CONTEXT
6 #include "EXTERN.h"
7 #include "perl.h"
8 #include "XSUB.h"
9 #define U8 U8
10 #include "encode.h"
11 # define PERLIO_FILENAME "PerlIO/encoding.pm"
12
13 /* set 1 or more to profile.  t/encoding.t dumps core because of
14    Perl_warner and PerlIO don't work well */
15 #define ENCODE_XS_PROFILE 0 
16
17 /* set 0 to disable floating point to calculate buffer size for
18    encode_method().  1 is recommended. 2 restores NI-S original */
19 #define ENCODE_XS_USEFP   1 
20
21 #define UNIMPLEMENTED(x,y) y x (SV *sv, char *encoding) {dTHX;   \
22                          Perl_croak(aTHX_ "panic_unimplemented"); \
23                          return (y)0; /* fool picky compilers */ \
24                          }
25 /**/
26 UNIMPLEMENTED(_encoded_utf8_to_bytes, I32)
27 UNIMPLEMENTED(_encoded_bytes_to_utf8, I32)
28
29 void
30 Encode_XSEncoding(pTHX_ encode_t * enc)
31 {
32     dSP;
33     HV *stash = gv_stashpv("Encode::XS", TRUE);
34     SV *sv = sv_bless(newRV_noinc(newSViv(PTR2IV(enc))), stash);
35     int i = 0;
36     PUSHMARK(sp);
37     XPUSHs(sv);
38     while (enc->name[i]) {
39         const char *name = enc->name[i++];
40         XPUSHs(sv_2mortal(newSVpvn(name, strlen(name))));
41     }
42     PUTBACK;
43     call_pv("Encode::define_encoding", G_DISCARD);
44     SvREFCNT_dec(sv);
45 }
46
47 void
48 call_failure(SV * routine, U8 * done, U8 * dest, U8 * orig)
49 {
50     /* Exists for breakpointing */
51 }
52
53
54 static SV *
55 encode_method(pTHX_ encode_t * enc, encpage_t * dir, SV * src,
56               int check)
57 {
58     STRLEN slen;
59     U8 *s = (U8 *) SvPV(src, slen);
60     STRLEN tlen  = slen;
61     STRLEN ddone = 0;
62     STRLEN sdone = 0;
63
64     /* We allocate slen+1.
65        PerlIO dumps core if this value is smaller than this. */
66     SV *dst = sv_2mortal(newSV(slen+1));
67     U8 *d = (U8 *)SvPVX(dst);
68     STRLEN dlen = SvLEN(dst)-1;
69     int code;
70
71     if (!slen){
72         SvCUR_set(dst, 0);
73         SvPOK_only(dst);
74         goto ENCODE_END;
75     }
76
77     while (code = do_encode(dir, s, &slen, d, dlen, &dlen, !check))
78     {
79         SvCUR_set(dst, dlen+ddone);
80         SvPOK_only(dst);
81         
82         if (code == ENCODE_FALLBACK || code == ENCODE_PARTIAL){
83             break;
84         }
85         switch (code) {
86         case ENCODE_NOSPACE:
87         {       
88             STRLEN more = 0; /* make sure you initialize! */
89             STRLEN sleft;
90             sdone += slen;
91             ddone += dlen;
92             sleft = tlen - sdone;
93 #if ENCODE_XS_PROFILE >= 2
94             Perl_warn(aTHX_
95                       "more=%d, sdone=%d, sleft=%d, SvLEN(dst)=%d\n",
96                       more, sdone, sleft, SvLEN(dst));
97 #endif
98             if (sdone != 0) { /* has src ever been processed ? */
99 #if   ENCODE_XS_USEFP == 2
100                 more = (1.0*tlen*SvLEN(dst)+sdone-1)/sdone
101                     - SvLEN(dst);
102 #elif ENCODE_XS_USEFP
103                 more = (1.0*SvLEN(dst)+1)/sdone * sleft;
104 #else
105                 /* safe until SvLEN(dst) == MAX_INT/16 */
106                 more = (16*SvLEN(dst)+1)/sdone/16 * sleft;
107 #endif
108             }
109             more += UTF8_MAXLEN; /* insurance policy */
110             d = (U8 *) SvGROW(dst, SvLEN(dst) + more);
111             /* dst need to grow need MORE bytes! */
112             if (ddone >= SvLEN(dst)) {
113                 Perl_croak(aTHX_ "Destination couldn't be grown.");
114             }
115             dlen = SvLEN(dst)-ddone-1;
116             d   += ddone;
117             s   += slen;
118             slen = tlen-sdone;
119             continue;
120         }
121         case ENCODE_NOREP:
122             /* encoding */      
123             if (dir == enc->f_utf8) { 
124                 STRLEN clen;
125                 UV ch =
126                     utf8n_to_uvuni(s+slen, (SvCUR(src)-slen), 
127                                    &clen, UTF8_ALLOW_ANY|UTF8_CHECK_ONLY);
128                 if (check & ENCODE_DIE_ON_ERR) {
129                     Perl_croak(
130                         aTHX_ "\"\\N{U+%" UVxf "}\" does not map to %s, %d", 
131                         ch, enc->name[0], __LINE__);
132                 }else{
133                     if (check & ENCODE_RETURN_ON_ERR){
134                         if (check & ENCODE_WARN_ON_ERR){
135                             Perl_warner(
136                                 aTHX_ packWARN(WARN_UTF8),
137                                 "\"\\N{U+%" UVxf "}\" does not map to %s", 
138                                 ch,enc->name[0]);
139                         }
140                         goto ENCODE_SET_SRC;
141                     }else if (check & ENCODE_PERLQQ){
142                         SV* perlqq = 
143                             sv_2mortal(newSVpvf("\\x{%04x}", ch));
144                         sdone += slen + clen;
145                         ddone += dlen + SvCUR(perlqq);
146                         sv_catsv(dst, perlqq);
147                     } else { 
148                         /* fallback char */
149                         sdone += slen + clen;
150                         ddone += dlen + enc->replen; 
151                         sv_catpvn(dst, (char*)enc->rep, enc->replen); 
152                     }                   
153                 } 
154             }
155             /* decoding */
156             else {           
157                 if (check & ENCODE_DIE_ON_ERR){
158                     Perl_croak(
159                         aTHX_ "%s \"\\x%02X\" does not map to Unicode (%d)",
160                         enc->name[0], (U8) s[slen], code);
161                 }else{
162                     if (check & ENCODE_RETURN_ON_ERR){
163                         if (check & ENCODE_WARN_ON_ERR){
164                             Perl_warner(
165                                 aTHX_ packWARN(WARN_UTF8),
166                                 "%s \"\\x%02X\" does not map to Unicode (%d)",
167                                 enc->name[0], (U8) s[slen], code);
168                         }
169                         goto ENCODE_SET_SRC;
170                     }else if (check & ENCODE_PERLQQ){
171                         SV* perlqq = 
172                             sv_2mortal(newSVpvf("\\x%02X", s[slen]));
173                         sdone += slen + 1;
174                         ddone += dlen + SvCUR(perlqq);
175                         sv_catsv(dst, perlqq);
176                     } else {
177                         sdone += slen + 1;
178                         ddone += dlen + strlen(FBCHAR_UTF8); 
179                         sv_catpv(dst, FBCHAR_UTF8); 
180                     }
181                 }
182             }
183             /* settle variables when fallback */
184             d    = (U8 *)SvEND(dst);
185             dlen = SvLEN(dst) - ddone - 1;
186             s    = (U8*)SvPVX(src) + sdone; 
187             slen = tlen - sdone;
188             break;
189
190         default:
191             Perl_croak(aTHX_ "Unexpected code %d converting %s %s",
192                        code, (dir == enc->f_utf8) ? "to" : "from",
193                        enc->name[0]);
194             return &PL_sv_undef;
195         }
196     }
197  ENCODE_SET_SRC:
198     if (check && !(check & ENCODE_LEAVE_SRC)){
199         sdone = SvCUR(src) - (slen+sdone);
200         if (sdone) {
201             sv_setpvn(src, (char*)s+slen, sdone);
202         }
203         SvCUR_set(src, sdone);
204     }
205     /* warn("check = 0x%X, code = 0x%d\n", check, code); */
206     if (code && !(check & ENCODE_RETURN_ON_ERR)) {
207         return &PL_sv_undef;
208     }
209     
210     SvCUR_set(dst, dlen+ddone);
211     SvPOK_only(dst);
212     
213 #if ENCODE_XS_PROFILE
214     if (SvCUR(dst) > SvCUR(src)){
215         Perl_warn(aTHX_
216                   "SvLEN(dst)=%d, SvCUR(dst)=%d. %d bytes unused(%f %%)\n",
217                   SvLEN(dst), SvCUR(dst), SvLEN(dst) - SvCUR(dst),
218                   (SvLEN(dst) - SvCUR(dst))*1.0/SvLEN(dst)*100.0);
219     }
220 #endif
221     
222  ENCODE_END:
223     *SvEND(dst) = '\0';
224     return dst;
225 }
226
227 MODULE = Encode         PACKAGE = Encode::XS    PREFIX = Method_
228
229 PROTOTYPES: ENABLE
230
231 void
232 Method_name(obj)
233 SV *    obj
234 CODE:
235 {
236     encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
237     ST(0) = sv_2mortal(newSVpvn(enc->name[0],strlen(enc->name[0])));
238     XSRETURN(1);
239 }
240
241 void
242 Method_decode(obj,src,check = 0)
243 SV *    obj
244 SV *    src
245 int     check
246 CODE:
247 {
248     encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
249     ST(0) = encode_method(aTHX_ enc, enc->t_utf8, src, check);
250     SvUTF8_on(ST(0));
251     XSRETURN(1);
252 }
253
254 void
255 Method_encode(obj,src,check = 0)
256 SV *    obj
257 SV *    src
258 int     check
259 CODE:
260 {
261     encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
262     sv_utf8_upgrade(src);
263     ST(0) = encode_method(aTHX_ enc, enc->f_utf8, src, check);
264     XSRETURN(1);
265 }
266
267 void
268 Method_needs_lines(obj)
269 SV *    obj
270 CODE:
271 {
272     encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
273     ST(0) = &PL_sv_no;
274     XSRETURN(1);
275 }
276
277 void
278 Method_perlio_ok(obj)
279 SV *    obj
280 CODE:
281 {
282     encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
283     if (hv_exists(get_hv("INC", 0), 
284                   PERLIO_FILENAME, strlen(PERLIO_FILENAME)))
285     {
286         ST(0) = &PL_sv_yes;
287     }else{
288         ST(0) = &PL_sv_no;
289     }
290     XSRETURN(1);
291 }
292
293 MODULE = Encode         PACKAGE = Encode
294
295 PROTOTYPES: ENABLE
296
297 I32
298 _bytes_to_utf8(sv, ...)
299 SV *    sv
300 CODE:
301 {
302     SV * encoding = items == 2 ? ST(1) : Nullsv;
303     
304     if (encoding)
305     RETVAL = _encoded_bytes_to_utf8(sv, SvPV_nolen(encoding));
306     else {
307         STRLEN len;
308         U8*    s = (U8*)SvPV(sv, len);
309         U8*    converted;
310
311         converted = bytes_to_utf8(s, &len); /* This allocs */
312         sv_setpvn(sv, (char *)converted, len);
313         SvUTF8_on(sv); /* XXX Should we? */
314         Safefree(converted);                /* ... so free it */
315         RETVAL = len;
316     }
317 }
318 OUTPUT:
319     RETVAL
320
321 I32
322 _utf8_to_bytes(sv, ...)
323 SV *    sv
324 CODE:
325 {
326     SV * to    = items > 1 ? ST(1) : Nullsv;
327     SV * check = items > 2 ? ST(2) : Nullsv;
328
329     if (to) {
330         RETVAL = _encoded_utf8_to_bytes(sv, SvPV_nolen(to));
331     } else {
332         STRLEN len;
333         U8 *s = (U8*)SvPV(sv, len);
334
335         RETVAL = 0;
336         if (SvTRUE(check)) {
337             /* Must do things the slow way */
338             U8 *dest;
339             /* We need a copy to pass to check() */
340             U8 *src  = (U8*)savepv((char *)s); 
341             U8 *send = s + len;
342
343             New(83, dest, len, U8); /* I think */
344
345             while (s < send) {
346                 if (*s < 0x80){
347                     *dest++ = *s++;
348                 } else {
349                     STRLEN ulen;
350                     UV uv = *s++;
351
352                     /* Have to do it all ourselves because of error routine,
353                        aargh. */
354                     if (!(uv & 0x40)){ goto failure; }
355                     if      (!(uv & 0x20)) { ulen = 2;  uv &= 0x1f; }
356                     else if (!(uv & 0x10)) { ulen = 3;  uv &= 0x0f; }
357                     else if (!(uv & 0x08)) { ulen = 4;  uv &= 0x07; }
358                     else if (!(uv & 0x04)) { ulen = 5;  uv &= 0x03; }
359                     else if (!(uv & 0x02)) { ulen = 6;  uv &= 0x01; }
360                     else if (!(uv & 0x01)) { ulen = 7;  uv = 0; }
361                     else                   { ulen = 13; uv = 0; }
362                 
363                     /* Note change to utf8.c variable naming, for variety */
364                     while (ulen--) {
365                         if ((*s & 0xc0) != 0x80){ 
366                             goto failure; 
367                         } else {
368                             uv = (uv << 6) | (*s++ & 0x3f);
369                         }
370                   }
371                   if (uv > 256) {
372                   failure:
373                       call_failure(check, s, dest, src);
374                       /* Now what happens? */
375                   }
376                   *dest++ = (U8)uv;
377                 }
378             }
379         } else {
380             RETVAL = (utf8_to_bytes(s, &len) ? len : 0);
381         }
382     }
383 }
384 OUTPUT:
385     RETVAL
386
387 bool
388 is_utf8(sv, check = 0)
389 SV *    sv
390 int     check
391 CODE:
392 {
393     if (SvGMAGICAL(sv)) /* it could be $1, for example */
394         sv = newSVsv(sv); /* GMAGIG will be done */
395     if (SvPOK(sv)) {
396         RETVAL = SvUTF8(sv) ? TRUE : FALSE;
397         if (RETVAL &&
398             check  &&
399             !is_utf8_string((U8*)SvPVX(sv), SvCUR(sv)))
400             RETVAL = FALSE;
401     } else {
402         RETVAL = FALSE;
403     }
404     if (sv != ST(0))
405         SvREFCNT_dec(sv); /* it was a temp copy */
406 }
407 OUTPUT:
408     RETVAL
409
410 SV *
411 _utf8_on(sv)
412 SV *    sv
413 CODE:
414 {
415     if (SvPOK(sv)) {
416         SV *rsv = newSViv(SvUTF8(sv));
417         RETVAL = rsv;
418         SvUTF8_on(sv);
419     } else {
420         RETVAL = &PL_sv_undef;
421     }
422 }
423 OUTPUT:
424     RETVAL
425
426 SV *
427 _utf8_off(sv)
428 SV *    sv
429 CODE:
430 {
431     if (SvPOK(sv)) {
432         SV *rsv = newSViv(SvUTF8(sv));
433         RETVAL = rsv;
434         SvUTF8_off(sv);
435     } else {
436         RETVAL = &PL_sv_undef;
437     }
438 }
439 OUTPUT:
440     RETVAL
441
442 PROTOTYPES: DISABLE
443
444
445 int
446 DIE_ON_ERR()
447 CODE:
448     RETVAL = ENCODE_DIE_ON_ERR;
449 OUTPUT:
450     RETVAL
451
452 int 
453 WARN_ON_ERR()
454 CODE:
455     RETVAL = ENCODE_WARN_ON_ERR;
456 OUTPUT:
457     RETVAL
458
459 int
460 LEAVE_SRC()
461 CODE:
462     RETVAL = ENCODE_LEAVE_SRC;
463 OUTPUT:
464     RETVAL
465
466 int
467 RETURN_ON_ERR()
468 CODE:
469     RETVAL = ENCODE_RETURN_ON_ERR;
470 OUTPUT:
471     RETVAL
472
473 int
474 PERLQQ()
475 CODE:
476     RETVAL = ENCODE_PERLQQ;
477 OUTPUT:
478     RETVAL
479
480 int
481 FB_DEFAULT()
482 CODE:
483     RETVAL = ENCODE_FB_DEFAULT;
484 OUTPUT:
485     RETVAL
486
487 int
488 FB_CROAK()
489 CODE:
490     RETVAL = ENCODE_FB_CROAK;
491 OUTPUT:
492     RETVAL
493
494 int
495 FB_QUIET()
496 CODE:
497     RETVAL = ENCODE_FB_QUIET;
498 OUTPUT:
499     RETVAL
500
501 int
502 FB_WARN()
503 CODE:
504     RETVAL = ENCODE_FB_WARN;
505 OUTPUT:
506     RETVAL
507
508 int
509 FB_PERLQQ()
510 CODE:
511     RETVAL = ENCODE_FB_PERLQQ;
512 OUTPUT:
513     RETVAL
514
515 BOOT:
516 {
517 #include "def_t.h"
518 #include "def_t.exh"
519 }