package chkjis;
use strict;
#---------------------------------------------------------------------
# 機種依存文字フィルター・ライブラリ
#   JIS X 0208:1997 外の文字を下駄文字「〓」に変換
#   Copyright(C) 2002 MORIYAMA Masayuki (森山 将之)
#
# 再配布について
#   このライブラリを利用したアプリケーションを書かれた場合には、この
#   ライブラリそのものを添付していただいて構いません。
#   改造版の再配布については、ファイル名を変更して配布するようにして
#   ください。
#
# 無保証
#   このプログラムを使用することにより生じた損害については、作者はい
#   かなる理由においても責任を負いません。使用される方の責任において
#   お使いください。 
#
# ※注意点
#   &chkjis::filter(\$line, 'jis'); # (ISO-2022-JP)
#     ・2バイトコード文字列中に [\x80-\xFF] のコードが混じっている
#       と、それ以降の文字列を変換しません。
#     ・変換対象の文字集合は JIS X 0208 に限定され、JIS X 0213 や 
#       JIS X 0212 に関しては何も処理を行いません。
#     ・JIS X 0208 への切替を示すエスケープシーケンス ESC $ @ と 
#       ESC $ B そして ESC & @ ESC $ B の厳密な区別は行っていませ
#       ん。
# 
#   &chkjis::filter(\$line, 'euc'); # (EUC-JP)
#     ・文字列中に [\xA0\xFF] のコードが混じっているとそれ以降の文
#       字列を変換しません。
#     ・変換対象の文字集合は JIS X 0208 に限定され、JIS X 0212 に関
#       何も処理を行いません。
# 
#   &chkjis::filter(\$line, 'sjis'); # (Shift_JIS)
#     ・文字列中に 
#       [\x80\xA0\xFD-\xFF]|[\x81-\x9F\xE0-\xFC][\x00-\x3F\x7F\xFD-\xFF]
#       のコードが混じっていると、それ以降の文字を変換しません。
# 
#   - 変換打ち切りの動作で euc と sjis に関しては $euc, $sjis の正
#     規表現を変更する事で緩和する事は可能です。jis の動作に関して
#     は、エンスケープシーケンスの処理が絡むので、$jis の変更だけ
#     ではうまくいかないと思われます。
# 
#   文字コード指定について
#     chkjis.pl では、判定は行っていませんので、正しく文字コードを
#     指定する必要があります。
#     文字コードの指定がなかった場合は変換は行われません。
# 
#   JIS X 0208:1997 未定義領域のデータの信頼性について
#     一応チェックはしてありますが、正しい事を保証はいたしません。
#     もし間違い等を見つけましたらご連絡ください。
#---------------------------------------------------------------------
# 履歴
#   Version 0.17
#     2002/10/23 仮公開
#   Version 0.18
#     2002/10/23 get_version() 廃止 (Perl5 形式で our を使えばパッケー
#                の外から $chkjis::version を参照できると判ったため)
#---------------------------------------------------------------------

our $version = '0.18';

my $f_strict     = 0;
my $f_useG1kana  = 0;

my $geta_jis     = "\x22\x2E";
my $geta_euc     = "\xA2\xAE";
my $geta_sjis    = "\x81\xAC";

my $re_x0208     =  q{\e\$[\@B]};
my $re_x0212     =  q{\e\$\(D};
my $re_x0213     =  q{\e\$\([OP]};
my $re_asc       =  q{\e\([BJ]};
my $re_kana      =  q{\e\(I};
my $re_k7        =  q{\x21-\x5F};
my $re_k8        =  q{\xA1-\xDF};
my $re_jis_esc   = qq{$re_asc|$re_kana|$re_x0208|$re_x0212|$re_x0213};

my $esc_asc      = "\e(J";
my $esc_kana     = "\e(I";
my $SO           = "\x0E";
my $SI           = "\x0F";

# 7ビットJIS にマッチ
my $jis =
	   '[\x00-\x20\x7F]'
	. '|[\x21-\x7E][\x21-\x7E]';

# 7ビットJIS で JIS X 0208:1997 未定義領域(区単位)
my $undef_j = '[\x29-\x2F\x75-\x7E][\x21-\x7E]';

# 7ビットJIS で JIS X 0208:1997 未定義領域(厳密)
my $undef_j_strict =
	   '[\x29-\x2F\x75-\x7E][\x21-\x7E]'
	. '|\x22[\x2F-\x39\x42-\x49\x51-\x5B\x6B-\x71\x7A-\x7D]'
	. '|\x23[\x21-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]'
	. '|\x24[\x74-\x7E]'
	. '|\x25[\x77-\x7E]'
	. '|\x26[\x39-\x40\x59-\x7E]'
	. '|\x27[\x42-\x50\x72-\x7E]'
	. '|\x28[\x41-\x7E]'
	. '|\x4F[\x54-\x7E]'
	. '|\x74[\x27-\x7E]';

# EUC-JP にマッチ
my $euc =
	   '[\x00-\x7F]'
	. '|[\x8E\xA1-\xFE][\xA1-\xFE]'
	. '|\x8F[\xA1-\xFE][\xA1-\xFE]';

# EUC-JP で JIS X 0208:1997 未定義領域(区単位)
my $undef_e ='[\xA9-\xAF\xF5-\xFE][\xA1-\xFE]';

# EUC-JP で JIS X 0208:1997 未定義領域(厳密)
my $undef_e_strict = 
	   '[\xA9-\xAF\xF5-\xFE][\xA1-\xFE]'
	. '|\xA2[\xAF-\xB9\xC2-\xC9\xD1-\xDB\xEB-\xF1\xFA-\xFD]'
	. '|\xA3[\xA1-\xAF\xBA-\xC0\xDB-\xE0\xFB-\xFE]'
	. '|\xA4[\xF4-\xFE]'
	. '|\xA5[\xF7-\xFE]'
	. '|\xA6[\xB9-\xC0\xD9-\xFE]'
	. '|\xA7[\xC2-\xD0\xF2-\xFE]'
	. '|\xA8[\xC1-\xFE]'
	. '|\xCF[\xD4-\xFE]'
	. '|\xF4[\xA7-\xFE]';

# シフトJIS にマッチ
my $sjis =
	   '[\x00-\x7F\xA1-\xDF]'
	. '|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]';

# シフトJIS で JIS X 0208:1997 未定義領域(区単位)
my $undef_s =
	   '[\x85-\x87\xEB-\xFC][\x40-\x7E\x80-\xFC]'
	. '|\x88[\x40-\x7E\x80-\x9E]';

# シフトJIS で JIS X 0208:1997 未定義領域(厳密)
my $undef_s_strict =
	   '[\x85-\x87\xEB-\xFC][\x40-\x7E\x80-\xFC]'
	. '|\x81[\xAD-\xB7\xC0-\xC7\xCF-\xD9\xE9-\xEF\xF8-\xFB]'
	. '|\x82[\x40-\x4E\x59-\x5F\x7A-\x7E\x80\x9B-\x9E\xF2-\xFC]'
	. '|\x83[\x97-\x9E\xB7-\xBE\xD7-\xFC]'
	. '|\x84[\x61-\x6F\x92-\x9E\xBF-\xFC]'
	. '|\x88[\x40-\x7E\x80-\x9E]'
	. '|\x98[\x73-\x7E\x80-\x9E]'
	. '|\xEA[\xA5-\xFC]';

sub filter {
	my ($s, $code) = @_;
	my  $m;

	if    ($code eq 'sjis') { $m = &filter_sjis($s); }
	elsif ($code eq 'euc')  { $m = &filter_euc($s);  }
	elsif ($code eq 'jis')  { $m = &filter_jis($s);  }
	$m;
}

sub filter_jis {
	my ($s) = @_;
	my ($k, $m) = (0, 0);

	if ($f_useG1kana) {
		if (index($$s, $SO) > -1) {
			$k = $$s =~ s/$SO([$re_k7]*)$SI/$esc_kana$1$esc_asc/go;
			$$s =~ s/$re_kana$re_asc//go if $k;
		}
		$k += $$s =~ s/([$re_k8]+)/$esc_kana.chr(ord($1)-0x80).$esc_asc/geo;
		$$s =~ s/$re_asc($re_x0208)/$1/go if $k;
	}
	$$s =~ s/($re_x0208)([^\e]*)/&_filter_jis($1, $2, \$m)/geo;
	$m;
}

sub _filter_jis {
	my ($esc, $t, $rm) = @_;

	if ($f_strict) {
		$$rm += $t =~ s/\G((?:$jis)*?)(?:$undef_j_strict)/$1$geta_jis/go;
	} else {
		$$rm += $t =~ s/\G((?:$jis)*?)(?:$undef_j)/$1$geta_jis/go;
	}
	$esc . $t;
}

sub _del_esc {
	my ($t) = @_;

	$t =~ s/$re_jis_esc//go;
	$t;
}

sub filter_euc {
	my ($s) = @_;
	my  $m;

	if ($f_strict) {
		$m = $$s =~ s/\G((?:$euc)*?)(?:$undef_e_strict)/$1$geta_euc/go;
	} else {
		$m = $$s =~ s/\G((?:$euc)*?)(?:$undef_e)/$1$geta_euc/go;
	}
	$m;
}

sub filter_sjis {
	my ($s) = @_;
	my  $m;

	if ($f_strict) {
		$m = $$s =~ s/\G((?:$sjis)*?)(?:$undef_s_strict)/$1$geta_sjis/go;
	} else {
		$m = $$s =~ s/\G((?:$sjis)*?)(?:$undef_s)/$1$geta_sjis/go;
	}
	$m;
}

# オプション設定

sub ascii_esc {
	$esc_asc = shift || $esc_asc;
	$esc_asc = "\e\($esc_asc" if length($esc_asc) == 1;
}

sub strict      { $f_strict = 1;    }
sub nostrict    { $f_strict = 0;    }
sub useG1kana   { $f_useG1kana = 1; }
sub nouseG1kana { $f_useG1kana = 0; }
1;
