PerlIO の encoding layer の fallback ではまった
PerlIO の encoding layer は,$PerlIO::encoding::fallback
という変数に fallback type を指定しておくことができるみたい。ということを PerlIO::encoding - encoding layer - metacpan.org 見て知った。encoding いじるのに PerlIO 使うのはなんとなく敬遠してたんだけど,fallback できるんなら使う価値あるんじゃね,と思って,POD にしたがってコードを書いてみた。
#!/usr/bin/perl use strict; use warnings; use Encode; use PerlIO::encoding; local $PerlIO::encoding::fallback = Encode::FB_XMLCREF() ; my $output = q{}; open my $handle, '>', \$output or die "open: $!"; binmode $handle, ':encoding(cp932)' or die "binmode: $!"; print {$handle} "foo" . chr(0x2764); close $handle or die "close: $!"; print $output, "\n";
これを Perl 5.8.8 on RHEL 5.3 i386 で動かしてみた。
すると(ほぼ)POD に沿って書いたのに
Close with partial character at test.pl line 23. Close with partial character.
と怒られてしまう(ちなみにこいつは結構強力な exception で eval
でトラッピングできない)。
実は $PerlIO::encoding::fallback
の指定しているところを,
local $PerlIO::encoding::fallback = Encode::XMLCREF() ;
とするとうまくいって,
foo❤
のようになる。
気づいたきっかけは,PerlIO::encoding でデフォルトで指定されてる $fallback
が
our $fallback = Encode::PERLQQ()|Encode::WARN_ON_ERR()|Encode::STOP_AT_PARTIAL();
のようになっていたこと。
Encode - character encodings in Perl - metacpan.org をみるとわかるように,FB_XMLCREF
は XMLCREF | LEAVE_SRC
なんだけど,いろいろ試行錯誤してるとどうやら LEAVE_SRC
が悪さをするらしい。
上記コードでは XMLCREF
単独で指定しているけど,PerlIO::encoding のソースに倣って STOP_AT_PARTIAL
とかいう undocumented なフラグ等も指定しておいたほうがいいかもしんない。
気力と時間がないので原因は追ってない。環境依存なバグなのか POD のミスなのかバグなのか不明。Perl 5.10 だとうまくいくのかな?