The Man Who Fell From The Wrong Side Of The Sky:2010年1月19日分

[最新版] [一覧] [前月] [今月] [翌月]

2010/1/19(Tue)

[NetBSD] libedit I18N への道(その2)

先日の続きです

@ 出た!UTF-8!得意技!

先日監査した read.cでは、CHARSET_IS_UTF8というフラグが立っていた場合のみ国際化機能を有効にしていました。

337 #ifdef WIDECHAR
338         if (el->el_flags & CHARSET_IS_UTF8) {
339                 if (!utf8_islead((unsigned char)cbuf[0]))

このフラグは el.cの中でセットされています。

 88 #ifdef WIDECHAR
 89         if ((locale = setlocale(LC_CTYPE, NULL)) != NULL){
 90                 if (strcasestr(locale, ".UTF-8") != NULL)
 91                         el->el_flags |= CHARSET_IS_UTF8;
 92         }
 93 #endif

setlocale(3)で現在のLC_CTYPEカテゴリの設定値を取得し、".[Uu][Tt][Ff]-8"という文字列が含まれれば
Editline構造体elのel_flagsにCHARSET_IS_UTF8フラグのビットを立てるという処理です。

なぜUTF-8だけ特別扱い!という抗議は後回しにして、このコードそのものにも問題がある事を指摘しておきましょう。
それは「現在のlocaleの文字コード(CODESET)が何かを調べるために、locale nameの一部を切り出す」という行為
これそのものがマテガイ(馬刀貝、蟶貝とも。二枚貝綱マテガイ科の1種)であるということです。

@ それは実相寺いぞんです!

setlocale(3)に指定するlocale nameは

以外はすべて実装依存であることは以前もこの チラシの裏で書きました。

X/Open Portability Guide(XPG)では

	language [_territory] [.codeset] [@modifier]

という形式で言語以外はすべて省略可です、これよりのちの標準化の動きとしては
LI18NUX Locale Name Guidelineがありまして、こちらではCODESETは省略不可となったのですが
現状Linux/glibc2はXPGとの後方互換性を保つために、CODESETも省略可能のままです。
省略されてしまったら文字コードなんて拾えませんがな。

ただし省略した場合はen_USならISO8859-1、ja_JPならeucJPなどの、XPG時代のdense encodingとなるケースがほとんどです。
UTF-8 localeを使いたい場合は、明示的ににCODESETを指定する必要がありますので、Linux/glibc2ならうまくいくかもね。
# でもcanonical nameであるLANG=ja_JP.utf8だとマッチしないのだよね :P

@ Before Unicode, After Unicode

Unicodeもすでに 1/4世紀を経ています(Unixに至ってはもう40年…)、Unicode生誕以降にコンピュータ/情報処理が
伝来した言語+地域圏においては、この広大な21bitの幅を持つsparse encodingであるUTF-8がデフォルトなことが多いのです。

一例としてあげるならglibc2のaa_ET(Afar - Ethiopia) localeがあります。

	setlocale(LC_ALL, "aa_ET");

この場合、UTF-8なlocaleであるにもかかわらず、先ほどのCHARSET_IS_UTF8フラグは有効にはなりません。
libeditに祝福されたUTF-8のはずなのに、国際化機能による恩恵を受けることが出来ないわけです。

@ 文字コードを取得するだけであれば

上記のコードをもっとマシなものに書き改めるのであれば、nl_langinfo(3)を使うかでしょう。

#include <langinfo.h>
...
	char *codeset = nl_langinfo(CODESET);
	if (!strcmp(codeset, "UTF-8"))
		el->el_flags |= CHARSET_IS_UTF8;


これであれば、aa_ETだろうがen_US.UTF-8だろうが等しくlocaleの文字コード名を返します。

しかし困ったことに(?)これも返されるCODESETは実装依存です。文字列は"UTF-8"かもしれませんし
"utf8"かもしれません。もしかすると"Unicode Transformation Format 8"である可能性だってあるのです。
ですのでこのコードが予期したとおりに動くとは限りません、よって残念ながらsetlocale(LC_ALL, NULL)の戻り値も
nl_langinfo(CODESET)の戻り値もどちらもopaque(不透明)として扱うのが正しい姿勢でしょう。

@ イコール・ランゲージ・オポチュニティ

そもそもなぜUTF-8だけを特別扱い(神聖視?笑)する必要があるのでしょうか?
本来国際化機能というものは、全ての言語・地域の人間が等しく恩恵を受ける機会を得られるものでなければなりませんし
またその通りに実装されているはずです(足りない点は大いにありますが、例えばmulti-locale機能など)。

これに対して「Unicode/UTF-8は言語も地域も限定しない」と熱心なUnicodeのファンはいうでしょう。
しかし多くの国においてLegacy Encoding(日本ならeucJP、Shift_JISなど)が存在し
そもそも(その2)POSIX localeはそれらのことも考慮して設計されたものであるにもかかわらず
Unicode/UTF-8以外は足切りされて何の恩恵が受けられないというのはおかしな話です。

@ 次回

すいません、今日は力尽きました。

は次回に持ち越しということで。

まぁそもそもちゃんと何書くか決めないで行き当たりばったりのお筆先とか自動書記だからね(ぉ


[ホームへ] [ページトップへ]