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

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インタフェースは出ないのかね。

2005/10/21(Fri)

Citrusネタ

@mbrtowc/iconv internal

引き続き DR#288他

いや、この fetch_wchar(仮)の使い方ではありえないんです。 

よく読まずに脊髄反射してすいません。

私が以前漠然と考えてたインタフェースだと、mbrtowc(3)のように
マルチバイトとワイド文字をn:1で変換する機能を各モジュールで実装するより
mbsrtowcs(3)のようにm:nで変換する機能を実装した方が何かと便利
なのかなとか考えていましたが、ちょっとやり過ぎかな...↓こんなの。

/* プロトタイプ */
int fetch_wchars(void *ce, wchar_t *pws, size_t wslen,
	const char **pmb, size_t mblen, mbstate_t *pstate,
	int flag. size_t *pwsret, size_t *pmbret);
/*
引数
	ce     : (in)  ハンドル
	pws    : (out) 結果を格納するためのワイド文字変数へのポインタ
	wslen  : (in)  pwsに書き込み可能な最大長
	               1. シフト状態が確定した場合に最大変換されうるワイド文字
	                  の数を、WC_CUR_MAXマクロとして定義する
	                  (実装上の上限はWC_LEN_MAX)
	               2. シフト状態が確定して変換されたワイド文字数より
	                  wslenが小さい場合、wslenまでをpwsに書き込み、
	                  残りはpstateに保持して次回呼び出し時に書き込み
	pmb    : (in)  マルチバイト文字の先頭を指す変数へのポインタ
	         (out) 取得したマルチバイト文字の直後のバイトを指すよう更新される
	               L"\0"がpwsに格納された場合、NULLがセットされる
	               (pmbの終端'\0'ではないことに注意、UTF-5は"M"が終端になる)
	mblen  : (in)  pmbから読み込み可能な最大長
	               0がセットされた場合、L"\0"がpwsに格納されるまでの意味
	pstate : (in/out) 内部状態を保持している変数へのポインタ
	flag   : false - ワイド文字が1文字でも確定したときに変換を中断する、true - 続行 ※不要?
	pwsret : (out) pwsに書き込んだ長さ
	pmbret : (out) pmbから読み込んだ長さ
戻り値
	0      : 正常
	EINVAL : mbstate_tの状態が不正
	EILSEQ : バイトシーケンスが不正
*/
size_t
mbrtowc(wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
{
	int err;
	size_t wret, sret;

	if (ps == NULL)
		ps = mbrtowc_anonymous_state(ce);
	if (s == NULL) {
		mbstate_init(ce, ps);
		return is_encoding_state_depend(ce);
	}
	err = fetch_wchars(ce, pwc, 1, &s, n, ps, 0, &wret, &sret);
	if (err != 0) {
		errno = err;
		return (size_t)-1;
	}
	if (wret == 0)
		return (size_t)-2; /* restart */
	if (sret == 0)
		return (size_t)-3; /* DR#288 */
	if (s == NULL)
		return 0; /* L'\0' */
	return sret;
}
size_t
mbsrtowcs(wchar_t *pws, const char **s, size_t n, mbstate_t *ps)
{
	int err;
	size_t wret, sret;

	if (ps == NULL)
		ps = mbsrtowcs_anonymous_state(ce);
	err = fetch_wchars(ce, pws, n, s, 0/* until L'\0' */,
		ps, 1, &wret, &sret);
	if (err != 0) {
		errno = err;
		return (size_t)-1;
	}
	if (*s == NULL)
		--wret;
	return wret;
}
size_t
iconv(iconv_t cd, const char **src, size_t *srclen,
	char **dst, size_t *dstlen)
{
	wchar_t wcs[WC_LEN_MAX]; /* あるいは効率を求めてもっと大きなサイズ? */
	size_t wret, sret;

	do {
		err = fetch_wchars(ce, wcs, WC_CUR_MAX, src, *srclen, ps, 0, &wret, &sret);
		if (err != 0)
			goto error;
		*srclen += sret;
		/* wchar_t -> csid_t/index_t 変換 */
		/* csid_t/index_t -> wchar_t 変換 */
		/* wc -> mb 変換 & dst/dstlenへの書き込み */
	} while ...
}

ただこれSUSv6のmbsrtoswc(3)はmbrtowc(3)が内部で繰り返し呼ばれるという記述に違反気味です。
それとiconv(3)はこれでいけるのかまだ全然検証不足ですし、それ以外にも落とし穴があるかもね。

slhci_pcmcia?

こちらも情報ありがとうございます、高っ。
ってNetBSDはドライバないや...FreeBSDからパチれるかな。
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/dev/usb/slhci_pccard.c

2005/10/29(Sat)

Jornada710

某サードパーティー製、CFスロットにTYPE-2を刺せるようにする交換カバー
注文したら何の連絡も無いまま通販サイトが消滅した。( ゜д゜)<ニョガーン

REX-CFU1

@slhci_pcmcia.c

動くかどうかソース読んでみた。
dev/ic/sl811hs*が既にあるのでフロントエンドだけ書けば動くかもと
ちょっとワクテカしたんだけど、dev/usb/usb_mem.cあたりで
親からbus_dma_tag_tが貰える事が前提になってるんでpcmciaだと困る罠。
…って激しく既出ですかそうですか。
http://www.clave.gr.jp/ml/bsd-usb/200212/msg00009.html
http://mail-index.netbsd.org/port-i386/2004/05/02/0019.html

@逆の発想

usbにpcmciaスロットをくっつける
http://www.iodata.jp/prod/pccard/readerwriter/2003/usb2-pcadp/
NetBSDでも 使えるのに一瞬驚いたのだけど
usb>uhub>pcmcia>comじゃなくてusb>uhub>umodem>comと見えてるので納得。
REX-CFU1と夢の 数珠繋ぎは無理ですかそうですか、ってトップワロタ。
sig2で使うにはちょっと消費電力が大きくてpowerd HUB必須な予感。