Not only is the Internet dead, it's starting to smell really bad.:2005年10月20日分

2005/10/20(Thu)

ISO2022問題

引き続き 塩崎さんとこから。

@DR#288

case 2: /* 決定状態だが、まだ吐き出していないワイド文字がある */
	/* ぶっちゃけありえない */
	abort();

これってDR#288のケースですよね? abort()されると困ります。
zWという、例の CJK.infにも名前だけは登場するCESで発生しますので…

zWは名の通り"zW"というバイトシーケンスで始まる行はGB2312、それ以外はASCIIという7bit statefulなencodingです。

改行で初期シフト状態になります。

{ NONE, 0, { } }

行頭 'z' 1バイト読み込んだ段階ではASCII or GB2312は未決定です。

{ AMBIGIOUS, 1, { 'z' } }

続く2バイト目が非'W'(ここでは'a'とする)だった場合、mbstate_tの中身は

{ ASCII, 1, { 'a' } }

となり、stateはASCIIに決定し、wc = L'z'が返されます。
この時mbstate_t中に残された'a'は有効なASCII文字なんで、次回の呼び出し時にはL'a'として返され、入力文字は消費されません。
つまりwc != L'\0'なのにreturn 0というC99と矛盾する結果になります。

他にもUnicode Escape Sequence(\u0000とか\U00000000、GNU libiconvにはC99/Javaとして実装済)でも発生します。
"\U0000000@"のようなケースだと、最後でASCIIと判定されると吐き出してないワイド文字が9文字もmbstate_tに残ることになります。

このようなケースに対して、DR#288は(size_t)-3を返すことを提案し、mbrtoc(16|32)ではそれがそのまま採用されてるわけですが
こんな方法より「mbrtowcが0を返すときは文字の終端まで変換してL'\0'を返した場合」というISO-Cの仕様を削除するべきと思うんですけどね。
終端まで変換したか否かはwc == L'\0'か否かで判ることなんで。

	do {
		siz = mbrtowc(&wc, s, n, &ps);
		s += siz, n -= siz;
	} while (siz != 0);

ではなく

	do {
		siz = mbrtowc(&wc, s, n, &ps);
		s + size, n -= siz;
	} while (wc != L'\0');

と書けばよいだけですから。

LC_CTYPE=zh_CN.zW とか LC_CTYPE=C99 がぶっちゃけありないという意味なら 禿しく同意。

@(size_t)-3

mbrtoc16で(size_t)-3になるケースとしては

  • UTF-32 -> UTF-16
  • UTF-5(UCS4をbase32変換) -> UTF-16

なんかの場合に発生しますね。
マルチバイトをUCS4に変換した結果がBMP外なら、サロゲートペアつーことでchar16_t 2文字に変換されますが、
mbrtoc16はchar16_t 1文字ずつしか返せないので2文字目のchar16_tはmbstate_tの中に保管され、次回呼び出し時には
(size_t)-3と共に返されます。mbstate_tにまだまだ余裕のあるCitrusマンセー。

@NULL文字長

NULL文字の長さが判らんというのはmbrtowc(3)の欠陥ですがcitrusでは

const char *saved = s;
size_t spent;

err = mbrtowc_priv(ei, pwc, &s, n, ps, nresult);
...
spent = (size_t)s - saved;

で判らないことも無い状態で、実際にiconvはこれで判断してますよね。
ただ'\0'まで変換されてしまうと、sの指すポインタがrun outするのが個人的には嫌。

if (*pwc == 0)
    *nresult = 0;

をmbrtowc_priv内でやる必要はないと思っています。上でやりません?

@TODO

その他にも準備したほうがいいかも知れないのは
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1135.pdf
のwctomb_sなどの準備かな?

インタフェース的には今のmbrtowc_priv/wcrtomb_privで問題なさそうなんですが
mbrtowc_privの内部で_DIAGASSERT(exp)している制約条件に引っ掛かるとset_constraint_handler(3)でセットされる
関数ポインタが実行され、ユーザ定義の処理(ログやabort)を仕掛けることができる機能が追加されています。
ですので制約違反が発生したか否かを上位で検知できるようにするしないと。

あとはmbrtowc/wcrtombで扱うことが不可能なencodingをiconv的にどうするかとかも考えないと。
UTF-6のエンコードは圧縮率を決定するためにワイド文字列を
最初に全部読み込む必要があるんで今のwcrtombじゃ扱えません。mbstate_tなんてただの飾りです…

jornada710 + AH-F401U

よく考えたらスロットcarbusじゃないことに気づいて糸色望しました。
pcmciaじゃusbカードなんか無いよな...機種変するとsig2で困る罠。
WI-SIMってpcmciaインタフェースは出ないのかね。