[FreeBSD-users-jp 96345] Re: FreeBSD-11.2 の ja_JP.eucJP 環境

内藤 祐一郎 naito.yuichiro @ gmail.com
2018年 11月 6日 (火) 15:02:00 UTC


内藤です。

> FreeBSD ワークショップでも話が出た (出ない?) ようですが、

私がワークショップで話した内容は次の通りです。

11.2のソースのlib/libedit/read.c の L350-L378 に以下のコードがあり、
read(2) で1バイトずつ読み込んでは mbrtowc で wchar_t に変換するコードがあります。

		switch (ct_mbrtowc(cp, cbuf, cbp)) {
		case (size_t)-1:
			if (cbp > 1) {
				/*
				 * Invalid sequence, discard all bytes
				 * except the last one.
				 */
				cbuf[0] = cbuf[cbp - 1];
				cbp = 0;
				break;
			} else {
				/* Invalid byte, discard it. */
				cbp = 0;
				goto again;
			}
		case (size_t)-2:
			/*
			 * We don't support other multibyte charsets.
			 * The second condition shouldn't happen
			 * and is here merely for additional safety.
			 */
			if ((el->el_flags & CHARSET_IS_UTF8) == 0 ||
			    cbp >= MB_LEN_MAX) {
				errno = EILSEQ;
				*cp = L'\0';
				return -1;
			}
			/* Incomplete sequence, read another byte. */
			goto again;

mbrtowc()ではlocaleに従いバイト列を wchar_t に変換するわけですが、
eucJP や UTF-8 では当然1バイト読んだだけでは変換できません。
2バイト目や3バイト目が必要なため、mbrtowc()は -2 を返し、
続きを読み込んでくれと返しますが、呼び出し元では
el_flags に CHARSET_IS_UTF8 のフラグが立っていないとリトライせずに
エラー終了します。

libedit のこの関数(read_char)がエラー終了すると /bin/sh は標準入力が
閉じられたのと同じ動作をして終了してしまいます。

このCHARSET_IS_UTF8 がどこで立てられているのかと言うと、
lib/libedit/el.c:L97-105 の部分なのですが、

	/*
         * Initialize all the modules. Order is important!!!
         */
	el->el_flags = 0;
	if (setlocale(LC_CTYPE, NULL) != NULL){
		if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
			el->el_flags |= CHARSET_IS_UTF8;
	}

この処理は /bin/sh の起動直後で ~/.profile が読み込まれる前に実行されます。
そのため、/bin/sh の起動時に locale が UTF-8 だと UTF-8 は扱えますが、
ログインシェルのように /bin/sh の起動時の locale が C だと UTF-8 が通りません。

試しに /etc/login.conf で locale を UTF-8 にすると /bin/sh の起動時に locale が
設定されるので、UTF-8が通るようになります。

また、見ての通り、locale が eucJP の場合も CHARSET_IS_UTF8 が立つことは
ありません。

ここで、locale を一切無視してに常に CHARSET_IS_UTF8 を立てるようにすると、
とりあえず eucJP も UTF-8 も通りましたが、eucJP の場合でヒストリに
ゴミが入る問題が手元では発生しましたので、使える状態ににはありませんでした。

と、ここまでがワークショップで話した内容です。

その後なのですが、私個人が eucJP を使いたいとは思っていないこともあり
調査は進んでいません。

UTF-8 を通すだけのパッチならば、先ほどの CHARSET_IS_UTF8 の初期化位置を
直せば良いので簡単なのですが、それでは解決になってませんから。。。

また、この内容では平林さんの /bin/sh の parser.h が問題だという話は
全く無関係に思いますし、渡辺さんの UTF-8 では入力できたという報告とも
矛盾します。

はてさて、真実はどこにといった感じもあり、あんまり進展していません。。。

-- 
内藤 祐一郎
naito.yuichiro @ gmail.com





freebsd-users-jp メーリングリストの案内