[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[debian-devel:15366] Re: bash の初期化がおかしい



小池@JAISTです。

提示していただいた以下の patch で正しく動作する事を、こちらでも確認し
ました。

>>>>> In [debian-devel : No.15364] 
>>>>>	ukai@debian.or.jp (Fumitoshi UKAI) wrote:
> --- bash-2.05b.orig/lib/readline/nls.c	2001-10-16 03:32:29.000000000 +0900
> +++ bash-2.05b/lib/readline/nls.c	2002-10-29 14:36:46.000000000 +0900
> @@ -85,9 +85,14 @@
>     value, and go into eight-bit mode if it's not C or POSIX. */
>  #if defined (HAVE_SETLOCALE)
>    char *t;
> +  char *lspec;
 
> +  lspec = sh_get_env_value("LC_ALL");
> +  if (lspec == 0) lspec = sh_get_env_value("LC_CTYPE");
> +  if (lspec == 0) lspec = sh_get_env_value("LANG");
>    /* Set the LC_CTYPE locale category from environment variables. */
> -  t = setlocale (LC_CTYPE, "");
> +  // t = setlocale (LC_CTYPE, "");
> +  t = setlocale (LC_CTYPE, lspec);
>    if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
>      {
>        _rl_meta_flag = 1;

ただ、元のコードが以下の様なもので、

   1    char *t;
   2    t = setlocale (LC_CTYPE, "");

patch 後のコードは以下の様になる訳ですが、

   1    char *t;
   2    char *lspec;
   3    lspec = sh_get_env_value("LC_ALL");
   4    if (lspec == 0) lspec = sh_get_env_value("LC_CTYPE");
   5    if (lspec == 0) lspec = sh_get_env_value("LANG");
   6    t = setlocale (LC_CTYPE, lspec);

いずれの場合も、LC_ALL か LANG の少なくとも1つ(LC_CTYPE は除く)が、設
定されてものと仮定します。

鵜飼さんが作られた patch の場合には、LC_ALL, LC_CTYPE, LANG の順で探索
して、環境変数が定義されていれば、LC_CTYPE の設定にそれを使う、という
事を明示して書かれていると解釈しました。

ですが、setlocale の man page の 50 行目からの段落を読むと、なさった環
境変数の探索は、setlocale(LC_CTYPE, "") の内部でなされる事が保証される
事が、setlocale の仕様として定められていると読めます。

以下、その部分の引用です。適当に桁折りしてあります。

> For glibc, first (regardless of category), the environment variable
> LC_ALL is inspected, next the environment variable with the same
> name as the category (LC_COLLATE, LC_CTYPE, LC_MESSAGES,
> LC_MONETARY, LC_NUMERIC, LC_TIME) and finally the environment
> variable LANG. The first existing environment variable is used.

ですので、元のコード setlocale(LC_CTYPE, "") と同じ動作になると思われ
ますが、いかがでしょうか?

# LC_CTYPE が明示して定義してあれば、元のコードと鵜飼さんのコードの動
# 作は(特に LANG と LC_CTYPE が異なる場合には)違う動作を行うと思います
# が、久保田さんの記事では特にふれておられませんし、私が確認した環境で
# も環境変数 LC_CTYPE は定義しておりません。


それとも、

>  1) ~/.bashrc の LANG=ja_JP.eucJP が処理される
>    => setlocale(LC_ALL, "ja_JP.eucJP")

この段階で setenv("LANG", "ja_JP.eucJP") の様な処理がなされないままで、
setlocale(LC_CTYPE, "") が行なわれる為に問題が発生する、という事でしょ
うか?でしたら、そちらの方が本質的な問題だと思われます。まだコードを追っ
てないので、そう行えない、他の要因があるのかもしれませんが。


あと、ここからが本題なのですが、前のメールでも書きましたが、Solaris 7
(Solaris 2.7 は間違いです^^;)では、元のコードで問題無く動作します。微
妙に動作が異なる、特にLC_CTYPE と LC_MESSAGES の設定が異なる場合の動作
は Linux と Solaris で異なっているので、どちらが正しいのか分からないと
(もし、標準のロケールの動作の定義があるのなら)、どちらが問題だとも言え
ないのですが。

例えば、Solaris と Linux で、

     1  #include <stdio.h>
     2  #include <locale.h>
     3  #include <string.h>
     4  #include <errno.h>
     5
     6  int main()
     7  {
     8    setlocale(LC_ALL, "ja_JP.eucJP");
     9    setlocale(LC_CTYPE, "C");
    10    puts(strerror(ENOENT));
    11    return 0;
    12  }

というようなコードを実行させますと、Linux では ?????????????????????? 
と表示されるのは、今回の問題と同じような動作なのですが、Solaris の場合
には、「ファイルもディレクトリもありません。」と、日本語(EUC-JP)で表示
されてしまいます。今回の件も、この辺りの挙動の差異に似ているので、そう
ではないかと私は考えています。

その点をふまえてざっとコードを読んでみたのですが、locale.c 内で行って
いるロケール関連の処理が、ややおかしいと思えます。まだちゃんと読んでな
いので具体的な話が出来ないのが申し訳ないのですが、前述の LC_CTYPE と
LC_MESSAGES (や、LC_ALL、LANG等)の設定が異なる事があるように思える箇所
がいくつかあります。

# 鵜飼さんの patch は、その不整合な状態を、修正が必要な段階になってか
# ら整合性のある状態にしているように思われます。ですので、結果的に正し
# い動作になったのではないでしょうか。間違いという事も無いと思いますが、
# 正しいとも言えない気がします。だからと言って、問題が発生する事も無い
# と思いますけど。

話が散慢になってしまいましたが、要は何が言いたいかと言うと、「もうちょっ
と問題の根が深いのではないだろうか」という事です。普通は 
setlocale(LC_ALL, "") だけすればだいたい良いのに、LC_CTYPE や 
LC_MESSAGES などを個別に設定しているようなので、結構問題が複雑になって
いるように思えます。

# shell なので、やみくもに自分自身の環境変数を変更できない事情もあるの
# でしょうが。後付けで足しているのも問題なのかもしれませんが。

何の解決にもなっていないのですが、すいません。自分でも、もう少し調べて
みます。

-- 
こいけ@じゃいすと(がくせい) <s-koike@xxxxxxxxxxx>