蝉は、やがて死ぬる午後に気づいた。ああ、私たち、もっと仕合せになってよかったのだ。:2006年03月31日分

2006/03/31(Fri)

iconv ``RAW'' conversion

ところでGNU libiconvは

JIS_X0201-1976
JIS_X0208-1983
JIS_X0212-1990
KSC5601
GB2312-80

のような符号化文字集合の「生」変換をサポートしている。
compound text + X11を介さずにbdf fontを操作する場合なんかに使うんだろうかね。
以下実行結果。

$ echo -n "あ" | /usr/pkg/bin/iconv -f EUC-JP -t JIS_X0208-1983 | od -c
0000000   $   "
0000002

NetBSD/Citrusでとりあえず実装するならlibISO2022.soのパラメタに

NAME		"JISX0208-RAW"
ENCODING	"ISO2022"
VARIABLE	"INIT0=94$B"
DEFCSID		"JISX0208:1990" 0x42007F00
INVALID		0x4200222E # GETA

とセットすればよいはず。
多分libEUC.so のように性能向上の為に専用モジュール書いたほうがいいんだろうけど。

$ echo -n "あ" | iconv -f EUC-JP -t JISX0208-RAW | od -c
0000000    $   " 033   (   B
0000005

うーん余計なエスケープシーケンスがついてしまうがな。

1034	if (iscntl(wc & 0xff)) {
1035		/* go back to ASCII on control chars */
1036		cs.type = CS94;
1037		cs.final = 'B';
1038		cs.interm = '\0';
1039	} else if (!(wc & ~0xff)) {

ここは制御文字がきたらASCIIに強制的に戻すんじゃなくて

static const _ISO2022Charset ascii = { CS94, 'B', '\0', '\0' };
static const _ISO2022Charset iso88591 = { CS94, 'A', '\0', '\0' };
...
	if (isc0(wc & 0xff))
		/* go back to INIT0 on C0 chars */
		cs = (ei->initg[0].final) ? ei->initg[0] : ascii;
	else if (isc1(wc & 0xff))
		/* go back to INIT1 on C1 chars */
		cs = (ei->initg[1].final) ? ei->initg[1] : ascii;
	else if (!(wc & ~0xff)) {

こんな感じでC0ならINIT0、C1ならINIT1に戻すが正解?、とりあえず上の対応をして再実行。

0000000    $   "  \0
0000003

まだゴミがついてくるね。
put_state_reset内でmbstate_tを初期化するために喰わせるL'\0'が変なことになってる。

1155	switch (cs.type) {
1156	case CS94:
1157	case CS96:
1158		i = 1;
1159		break;
1160	case CS94MULTI:
1161	case CS96MULTI:
1162		i = isthree(cs.final) ? 3 : 2;
1163		break;
1164	}
1165	while (i-- > 0)
1166		*p++ = ((wc >> (i << 3)) & 0x7f) | mask;

ここだね。
ワイド文字が制御文字にも関わらず2バイトに水増しされてしまう、ここも修正すれば多分OK。