[FreeBSD][nl_langinfo][BSD][Cygwin][MacOSX] FreeBSD の nl_langinfo() がひどい件について
UTF-8 Cygwin 上の zsh とか、Mac OS X 上の Vim とかで同時多発的 *1にLANG=ja_JP.UTF-8 を指定したい要求が出てきて、でも、いくら LANG や LC_CTYPE 設定しても US-ASCII としかみなされないという妙な現象に悩まされていた今日この頃だったのですが、その原因がことごとく判明。
case CODESET: ret = ""; if ((s = setlocale(LC_CTYPE, NULL)) != NULL) { if ((cs = strchr(s, '.')) != NULL) { ret = cs + 1; #ifdef TRANSITION_PERIOD_HACK if (strncmp(ret, "ISO_", 4) == 0) { int slen = strlen(ret); if ((cset = reallocf(cset, slen)) != NULL) { strcpy(cset, "ISO"); strcat(cset, ret + 4); ret = cset; } else ret = ""; } else if (strcmp(ret, "EUC") == 0) { if (strncmp(s, "ja_JP", 5) == 0) ret = "eucJP"; else if (strncmp(s, "ko_KR", 5) == 0) ret = "eucKR"; else if (strncmp(s, "zh_CN", 5) == 0) ret = "eucCN"; } else if (strcmp(ret, "ASCII") == 0) ret = "US-ASCII"; #endif /* TRANSITION_PERIOD_HACK */ } else if (strcmp(s, "C") == 0 || strcmp(s, "POSIX") == 0 #ifdef TRANSITION_PERIOD_HACK || strstr(s, "ASCII") != NULL #endif /* TRANSITION_PERIOD_HACK */ ) ret = "US-ASCII"; } break;
Cygwin の newlib (cygwin libc) も、Mac OS X に同梱の libc もこれだ。やれやれ ┐(´ー`)┌
追記: strcmp() に合致しない場合は "." の後の部分がそのまま返るようになっているのは 6.2 release でも一緒ですね。誤解していました。すみません。 (指摘していただいた akr さんに感謝)
あ、ちなみに 6.2 release の方は次のようになってます。
http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/locale/nl_langinfo.c?rev=1.17&content-type=text/x-cvsweb-markup
case CODESET: ret = ""; if ((s = setlocale(LC_CTYPE, NULL)) != NULL) { if ((cs = strchr(s, '.')) != NULL) ret = cs + 1; else if (strcmp(s, "C") == 0 || strcmp(s, "POSIX") == 0) ret = "US-ASCII"; }
これはおそらく、文字コードセットの名称の長さが n 文字以内とかいうのを前提に作っているコード (結構あると思う) では脆弱さの素になりますな。
*1:simultaneous の訳語。ぎこちない日本語だよなあ